How to copy files whose name contains number from 20 to 32
Solution 1
|
is the pipeline operator.
cp -r ~/copyDest/*2[0-9]|3[0-2]* ~/pasteDest
is the cp
command piped to the command whose name is the first file expanded from the 3[0-2]*
glob. For |
to be a glob alternation operator, it has be within (...)
in zsh
(but zsh
has a dedicated operator for number range matching) and @(...)
in ksh
(or bash
with extglob
on).
So, with zsh
:
cp -r ~/copyDest/(*[^0-9]|)<20-32>(|[^0-9]*) ~/pasteDest
Without the (*[^0-9]|)
, it would also match on foo120
With ksh
or bash -O extglob
(or use shopt -s extglob
within bash
) or zsh -o kshglob
(set -o kshglob
within zsh
), the equivalent (except for the order in which the files are copied) would look like:
(
LC_ALL=C
cp -r ~/copyDest/?(*[^0-9])*(0)@(2[0-9]|3[0-2])?([^0-9]*) ~/pasteDest
)
With ksh or bash, on most systems and most locales other than C, [0-9]
matches a lot more characters than 0123456789, hence the LC_ALL=C
(which also affects the glob expansion sorting order). If your file names contain only ASCII characters, you may omit it, as I don't think any locale on any sane system would have ASCII characters other than 0123456789 matched by [0-9]
. Other alternative is to replace [0-9]
with [0123456789]
.
Also note that except in zsh -o kshglob
, if the pattern doesn't match any file, cp
will be called with a literal .../?(*[^0-9])*(0)@(2[0-9]|3[0-2])?([^0-9]*)
argument (a valid though unlikely file name) which if it exists would then be copied (or cp
would return an error otherwise). In bash
, you can use the failglob
option to get a behaviour closer to zsh
's saner one (of cancelling the command if the pattern doesn't match).
Above we take special care of copying files named foo20.txt
, foo00020.txt
, but not foo120.txt
or foo200.txt
(even though their name contains 20). It still copies foo32.12.txt
or foo-1E-20.txt
or foo0x20.txt
files.
If you still want to copy foo120
or foo200
files, then it becomes much simpler:
zsh
:cp -r ~/copyDest/*<20-32>* ~/pasteDest
bash -O extglob
and co:cp -r ~/copyDest/*@(2[0123456789]|3[012])* ~/pasteDest
Solution 2
You failed to read the manual on shell pattern matching and assumed that it is the same as what is commonly called "regular expressions". Just the fact that the *
operator, that you use in your example, has a different meaning should be a hint that they are not the same.
With bash (and some other shells) you can use the {,}
operator for the desired effect:
cp -r ~/copyDest/*{2[0-9],3[0-2]}* ~/pasteDest
But beware there are differences. This is the same as writing
cp -r ~/copyDest/*2[0-9]* ~/copyDest/*3[0-2]* ~/pasteDest
That means if either of the patterns doesn't match any file, it will be passed as an argument to cp
, and cp
will complain that the file doesn't exist. You can set the nullglob
shell option to avoid that.
Solution 3
bash
approach. As a bonus it prints the numbers for which a matching file was not fou nd.
[steve@instance-2 ~]$ find copyDest pasteDest
copyDest
copyDest/file15
copyDest/file20
copyDest/file25
copyDest/file32
copyDest/file33
pasteDest
[steve@instance-2 ~]$ cp -pr ~/copyDest/*{20..32}* pasteDest
cp: cannot stat ‘/home/steve/copyDest/*21*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*22*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*23*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*24*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*26*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*27*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*28*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*29*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*30*’: No such file or directory
cp: cannot stat ‘/home/steve/copyDest/*31*’: No such file or directory
[steve@instance-2 ~]$ find copyDest pasteDest
copyDest
copyDest/file15
copyDest/file20
copyDest/file25
copyDest/file32
copyDest/file33
pasteDest
pasteDest/file20
pasteDest/file25
pasteDest/file32
[steve@instance-2 ~]$
Solution 4
When I need to deal with numbered files, I tend to use a for loop and seq
:
for i in $(seq 20 32); do cp -r ~/copyDest/*${i}* ~/pasteDest; done
Solution 5
Yoe need to do pattern matching, NOT regex matching. Look into your shell's man page. Try something like
ls *2[0-9]* *3[0-2]*
i.e. implement the alternation by supplying two patterns.
user317427
Updated on September 18, 2022Comments
-
user317427 almost 2 years
I want to copy files from the copyDest to pastDest that contain number from 20 to 32. What am I dong wrong?
cp -r ~/copyDest/*2[0-9]|3[0-2]* ~/pasteDest
Thanks.
-
Stéphane Chazelas over 5 yearsNote that it would copy a
foo200.txt
orfoo120.txt
file as well. -
Stéphane Chazelas over 5 yearsNote that it would copy a
foo200.txt
orfoo120.txt
file as well. -
Stéphane Chazelas over 5 yearsNote that it would copy a
foo200.txt
orfoo120.txt
file as well. -
RudiC over 5 years@Stéphane Chazelas: which is what the OP requested: "contain number from 20 to 32". 120 does contain such. But, I see your point.
-
Stéphane Chazelas over 5 yearsYes, it was a note, not an objection. Something the OP possibly hadn't considered.
-
Baptiste Candellier over 5 yearsThere's no need to be condescending... at first sight they look similar. The rest of the answer is useful though, thanks.
-
mr.spuratic over 5 yearsThis approach (or zsh's
<20-32>
) is cleanest as it doesn't require the human to reverse engineer a pattern from a numeric sequence. -
studog over 5 yearsThe OP's attempt, if it worked, would also match
foo200.txt
orfoo120.txt
so presumably those matches are prohibited by the larger unstated context of OP's situation; perhaps the log files are only numbered from 1 - 64. -
FeRD over 5 yearsI mean, absent some sort of additional constraints to the contrary,
foo200.txt
does contain the number "20" in its filename. -
ybungalobill about 3 yearsAlso the
-w
switch is useful if the numbers need to be padded with zeros:seq -w 0 100
.