How to copy files from one directory to another using regex?

Asked

Viewed 413 times

3

On the linux terminal, when I want to list files in a directory using regex, I do:

#exemplo listando arquivos começando com uma letra maiúscula
ls | grep -oP '^[A-Z].+'

The flag oP is used for output to show only the boxes (o) and so I can apply Perl regex (P).

I wish I could also use this feature to copy files between directories. To copy files without regex do, for example:

cp /Documents/file.txt .

Using regex, I tried:

cp ~/Downloads/ | grep -oP '(AB|HU).+' .

that returns the error:

grep: .cp: missing destination file operand after '/home/lucas/Downloads/'
Try 'cp --help' for more information.
: Is a directory

As I understand it, fate would be ., that is, the current directory, but it did not work.

How can I deal with this mistake?

2 answers

5


When using | (also known as "pipe"), each of the parts (both before and after the |) must be a complete command. Basically, the output of the first command becomes the input of the second, so that ls | grep ... function (the output of the command ls becomes the entrance of the grep, i.e., the grep uses the filenames to search according to the informed criteria).

So by doing cp ~/Downloads/ | grep -oP '(AB|HU).+' . actually he tries to run first cp ~/Downloads and then his departure would be sent to grep.
And the error occurs because cp ~/Downloads/ is not a complete command (he understands that you are saying you want to copy the Downloads directory, but does not say where). And even if it were a valid command, his exit would be sent to grep, which wouldn’t make much sense (because you actually want the result of grep be passed to cp).


If you want to copy files that start with a capital letter, you wouldn’t even need regex:

cp ~/Downloads/[[:upper:]]* .

But if the idea is to use regex (with some criteria more complex than "start with uppercase"), one option is to use find, and so that the exit from this one is passed to cp, use command substitution: just put the command between $( ). Thus:

cp $(find ~/Downloads -type f -regextype posix-egrep -regex ".*/(AB|HU).+") .

That is, the find finds the files, and how it is between $( ), the result of it (which are the filenames) is passed correctly to cp.

I didn’t use the original command (ls | grep) because the output only returns the file names without the folder name, so you would need to put the name in front again. Something like this:

cp $(ls ~/Downloads/ | grep -oP '^(AB|HU).+' | perl -p -e 's/^/$ENV{HOME}\/Downloads\//') .

Which in my opinion is far more confusing than the option with find.


Although for this particular case, the regex is ^(AB|HU).+ (starts with "AB" or "HU"), so you could also replace it with Brace Expansion:

cp ~/Downloads/{AB,HU}* .

Thus, it copies the files from the Downloads folder, whose names start with "AB" or "HU".

With Brace Expansion it is also possible to take all files starting with uppercase letter:

cp ~/Downloads/{A..Z}* .

The annoying detail is that in this case he will try to get all possible options (starts with "A", with "B", etc.), and if any of them does not exist, an error message will appear. If you want to omit these messages, do:

cp ~/Downloads/{A..Z}* . 2>/dev/null

Only this will also omit any other error messages, so for files that start with uppercase letter, I think it’s best to use the first option above ([[:upper:]]).

1

By the way a couple more variants (in the @hksotsubo continuum):

cp ~/Downloads/AB*  ~/Downloads/HU*  dir/

(that is to expand the alternative in some cases is an alternative)

Although to a limited extent we can use the reg operator. Exp [...]

cp ~/Downloads/[A-Z]*     dir/     ## copia os ficheiros começados por maiuscula
cp ~/Downloads/[AH][BU]*  dir/     ## copia AB* HU* mas tambem AU* e HB*

Browser other questions tagged

You are not signed in. Login or sign up in order to post.