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:]]
).
Tip: You can use the command
find
with the parameter-regex
using a function-exec
. Example: Find command with -regex and -exec– Rfroes87