I want to pass each output from a command as multiple argument to a second command, e.g.:
grep "pattern" input
returns:
file1
file2
file3
and I want to copy these outputs, e.g:
cp file1 file1.bac
cp file2 file2.bac
cp file3 file3.bac
How can I do that in one go? Something like:
grep "pattern" input | cp $1 $1.bac
In addition to Chris Jester-Young good answer, I would say that
xargs
is also a good solution for these situations:will make it. All together:
You can use
xargs
:You can use
$()
to interpolate the output of a command. So, you could usekill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'))
if you wanted to.For completeness, I'll also mention command substitution and explain why this is not recommended:
(The backtick syntax
cp `grep -l "pattern" input` directory/
is roughly equivalent, but it is obsolete and unwieldy; don't use that.)This will fail if the output from
grep
produces a file name which contains whitespace or a shell metacharacter.Of course, it's fine to use this if you know exactly which file names the
grep
can produce, and have verified that none of them are problematic. But for a production script, don't use this.Anyway, for the OP's scenario, where you need to refer to each match individually and add an extension to it, the
xargs
orwhile read
alternatives are superior anyway.In the worst case (meaning problematic or unspecified file names), pass the matches to a subshell via
xargs
:... where obviously the script inside the
for
loop could be arbitrarily complex.In the ideal case, the command you want to run is simple (or versatile) enough that you can simply pass it an arbitrarily long list of file names. For example, GNU
cp
has a-t
option to facilitate this use ofxargs
(the-t
option allows you to put the destination directory first on the command line, so you can put as many files as you like at the end of the command):which will expand into
for as many matches as
xargs
can fit onto the command line ofcp
, repeated as many times as it takes to pass all the files tocp
. (Unfortunately, this doesn't match the OP's scenario; if you need to rename every file while copying, you need to pass in just two arguments percp
invocation: the source file name and the destination file name to copy it to.)So in other words, if you use the command substitution syntax and
grep
produces a really long list of matches, you risk bumping intoARG_MAX
and "Argument list too long" errors; butxargs
will specifically avoid this by instead copying only as many arguments as it can safely pass tocp
at a time, and runningcp
multiple times if necessary instead.