How can i copy all the files in a folder and change the name in the same directory?

Viewed 133

i am having trouble trying to copy all the numbered files in a directory and change their names in the same directory but with same number, i am trying to do this:

cp rj1.text mike1.text
cp rj2.text mike2.text
cp rj3.text mike3.text
cp rj4.text mike4.text
cp rj5.text mike5.text
cp rj6.text mike6.text 

this is the code i tried using

cp /home/ryan/Desktop/rj/"rj*.text" /home/ryan/Desktop/rj/"mike*.text"

4 Answers

Since this is tagged [bash] you can use a simple parameter expansion with substring replacement to loop over the files replacing "rj" with "mike" as you copy each file.

For example You can do:

for f in *; do 
  cp "$f" "${f/rj/mike}"
done

(note: if you have more than just the "rj" files in the directory, you can replace the * glob with rj[[:digit:]].text to only match files with "rj" followed by a single-digit and the .text. Or, to just match digits 1-6, you can use rj[123456].txt or rj{1..6}.txt, up to you. The [123456] will work with all POSIX shells, the brace-expansion {1..6} is bash only)

Example Use/Output

Change to an empty directory and create the six file with "rj" in the name:

touch rj{1..6}.text

Now copy and change the name using the command above. The result you are wanting is now in the directory with both the "rj" and "mike" copies of the files, e.g.

$ tree
.
├── mike1.text
├── mike2.text
├── mike3.text
├── mike4.text
├── mike5.text
├── mike6.text
├── rj1.text
├── rj2.text
├── rj3.text
├── rj4.text
├── rj5.text
└── rj6.text

(note: to move the files from "rj" to "mike" removing the "rj" files, just use the mv command instead of cp)

I can only think of a multi-step process:

mkdir tmp
cd tmp
cp ../rj*.text ./
rename rj mike *.text
cp ./* ..
cd ..
rm -rf tmp

First of all, your wildcard * would not be expanded, because it is between single quotes and cp itself (like most commands) does not understand wildcards.

One possibility to do this in bash would be to shell out to zsh for this, because zsh hat the command zmv which does understand wildcards:

zsh -c "autoload zmv; zmv -Cv 'rj(*).txt' "'mike $1.txt'

The autoload is necessary, since zmv is not available in zsh automatically. The $1 refers to the expression between parenthesis.

If you need such a "copy with rename" more often, I would find it more sensible to create a separate script (say: copy_ren) for this:

#!/usr/local/bin/env zsh
autoload zmv
zmv -Cv $1 $2

and then call it (provided it is executable and in your PATH) by

copy_ren 'rj(*).txt' 'mike$1.txt'

Your attempt:

cp /home/ryan/Desktop/rj/"rj*.text" /home/ryan/Desktop/rj/"mike*.text"

cannot work for at least two reasons:

  • By quoting the glob patterns ("rj*.text" and "mike*.text") you prevent their expansion to the matching file names. Bash will really try to copy a file literally named /home/ryan/Desktop/rj/rj*.text to a file literally named /home/ryan/Desktop/rj/mike*.text.

  • Even if you do not quote the patterns they will expand as the list of all matching file names... except if there is none, in which case the pattern expands as itself by default. In your case, if you have the 6 files you listed and no mike files, after expansion by the shell the command will become (directory names removed for better readability):

    cp rj1.text rj2.text rj3.text rj4.text rj5.text rj6.text mike*.text
    

    and it will fail because copying more than one file is allowed only if the destination is a directory and you don't have a directory named mike*.text.

So you need a loop to copy the files individually. If your rj files can have any number, including with more than one digit, they can be matched exactly with the extglob bash option:

/home/ryan/Desktop/rj/rj+([0-9]).text

matches any file named /home/ryan/Desktop/rj/rjN.text where N is a number with one or more digits.

I suggest to also enable the nullglob option such that the pattern expands to the null string if no files match. Finally, a simple pattern substitution can produce the destination name:

shopt -s extglob nullglob
dir="/home/ryan/Desktop/rj/"
for file in "${dir}"rj+([0-9]).text; do
  cp "$file" "${file/${dir}rj/${dir}mike}"
done
Related