Reputation: 1
There are 3 txt files called
1.txt 2.txt 3.txt
I want to batch copy with the name
1.txt.cp 2.txt.cp 3.txt.cp
using the wildcard *
.
I entered the command cp *.txt *.txt.cp
but it isn't working.
cp : target *.txt.cp : is not a directory
What is the problem?
Upvotes: 0
Views: 3246
Reputation: 84579
About the easiest and robust way to do what you are attempting is to collect the files with find . -type f -name "*.txt"
which will find all files ending in ".txt"
below the current directory. To limit to just the current directory add -maxdepth 1
before -type ...
. To ensure filenames with spaces or other strange characters are correctly handled add the -print0
option to ensure the filenames are nul-termianted. Putting that altogether, you could collect the files with:
find . -maxdepth 1 -type f -name "*.txt" -print0
Now to process the files, copying them to add a .cp
ending (extension) to the filename, you can use GNU xargs
using the -0
option to handle the nul-terminated filenames and the -I '{}'
replace-str option to process each filename which will replace '{}'
in the xargs
command. Putting that together, you would have:
xargs -0 -I '{}' cp -a '{}' '{}.cp'
Above you simply copy (cp -a
) preserving attributes '{}'
to '{}.cp'
adding the .cp
extension.
Putting it altogether, you would simply pipe the find
output to xargs
, e.g.:
find . -maxdepth 1 -type f -name "*.txt" -print0 | xargs -0 -I '{}' cp -a '{}' '{}.cp'
If you want a full quick example, just create the files and then prove to yourself it works as intended, e.g.
$ touch {1..3}.txt
$ find . -maxdepth 1 -type f -name "*.txt" -print0 | xargs -0 -I '{}' cp -a '{}' '{}.cp'
Resulting files in the current directory:
$ ls -al [1-3]*
-rw-r--r-- 1 david david 0 Aug 24 19:07 1.txt
-rw-r--r-- 1 david david 0 Aug 24 19:07 1.txt.cp
-rw-r--r-- 1 david david 0 Aug 24 19:07 2.txt
-rw-r--r-- 1 david david 0 Aug 24 19:07 2.txt.cp
-rw-r--r-- 1 david david 0 Aug 24 19:07 3.txt
-rw-r--r-- 1 david david 0 Aug 24 19:07 3.txt.cp
Let me know if you have questions. There are many additional ways to tailor the find
command to match just what you want to find using regular expressions instead of simple file-globbing if needed.
Upvotes: 0
Reputation: 149085
If you are used to MS/Windown CMD shell, it is important to note that Unix system handle very differently the wild cards. MS/Windows has kept the MS/DOS rule that said that wild cards were not interpreted but were passed to the command. The command sees the wildcard characters and can handle the second *
in the command as noting where the match from the first should go, making copy ab.* cd.*
sensible.
In Unix (and derivatives like Linux) the shell is in charge of handling the wildcards and it replaces any word containing one with all the possible matches. The good news is that the command has not to care about that. But the downside is that if the current folder contains ab.txt ab.md5 cd.jpg, a command copy ab.* cd.*
will be translated into copy ab.txt ab.md5 cd.jpg
which is probably not want you would expect...
The underlying reason is Unix shells are much more versatile than the good old MS/DOS inherited CMD.EXE and do have simple to use for
and if
compound commands. Just look at @Halley Oliveira's answer for the syntax for your use case.
Upvotes: 1
Reputation: 389
Use: for i in *.txt; do cp "$i" "$i.cp"; done
Example:
$ ls -l *.txt
-rw-r--r-- 1 halley halley 20 out 27 08:14 1.txt
-rw-r--r-- 1 halley halley 25 out 27 08:14 2.txt
-rw-r--r-- 1 halley halley 33 out 27 08:15 3.txt
$ ls -l *.cp
ls: could not access '*.cp': File or directory does not exist
$ for i in *.txt; do cp "$i" "$i.cp"; done
$ ls -l *.cp
-rw-r--r-- 1 halley halley 20 out 27 08:32 1.txt.cp
-rw-r--r-- 1 halley halley 25 out 27 08:32 2.txt.cp
-rw-r--r-- 1 halley halley 33 out 27 08:32 3.txt.cp
$ for i in *.txt; do diff "$i" "$i.cp"; done
$
Upvotes: 2