How to copy and add prefix to file names in one step?

41,860

Solution 1

a for loop:

for f in *.c; do cp -- "$f" "$OTHERDIR/old#$f"; done

I often add the -v option to cp to allow me to watch the progress.

Solution 2

You can use shell globbing:

for f in *.c; do cp -- "$f" "$OTHERDIR/old#$f"; done

The for variable in GLOB format will expand the glob to all matching files/directories (excluding hidden-ones) and iterate over them, saving each in turn as $variable (in the example above, $f). So, the command I show will iterate over all non-hidden files, copying them and adding the prefix.

Solution 3

Here is a one-liner using xargs, tr and globbing. Might have some value.

echo *.c | tr ' ' '\n' | xargs -n1 -I{} cp "{}" "PREFIX{}"

This returns all files matching *.c as a space-separated string. Next, tr turns the extra spaces into newlines (N.B. did not test file names with spaces**). Then, xargs gets populated with each file name, and runs cp with the appropriate name and prefix.

*.c can be modified for other, useful globs. Other prefixes in the xargs and cp part can be used as well.

**for those with spaces in their filenames:

(requires find that supports -print0) Similar to above, we can use find to output a null-seperated list of files, and tweak xargs with a flag to separate on null

find . -name '*.c' -print0 | xargs -0 -n1 -I{} cp "{}" "PREFIX{}"
Share:
41,860

Related videos on Youtube

BlackCat
Author by

BlackCat

Updated on September 18, 2022

Comments

  • BlackCat
    BlackCat almost 2 years

    I want to copy and rename multiple c source files in a directory.

    I can copy like this:

    $ cp *.c $OTHERDIR
    

    But I want to give a prefix to all the file names:

    file.c --> old#file.c
    

    How can I do this in 1 step?

  • don_crissti
    don_crissti about 7 years
    Don't loop over find's output. Don't use grep to exclude file names when find alone can do it.
  • don_crissti
    don_crissti about 7 years
  • Scott - Слава Україні
    Scott - Слава Україні over 5 years
    And, if you had tested this with filenames containing spaces, you would have seen it fail.
  • TonyH
    TonyH over 5 years
    Thanks for call-out. I knew it probably failed but thought I had already procrastinated through enough of my workday with the first pass. 😀
  • alexandernst
    alexandernst almost 5 years
    If I do for f in /foo/bar/*.c, $f will contain the entire path, instead only the name of the file. How can I obtain only the name of the file?
  • terdon
    terdon almost 5 years
    @alexandernst either cd /foo/bar/; for f in *c, or use for f in /foo/bar/*.c; do name=${f##*/} ... or name=$(basename "$f").