如何将命令输出作为多个参数传递给另一个命令

时间:2021-03-03 13:55:58

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

4 个解决方案

#1


12  

You can use xargs:

你可以使用xargs:

grep 'pattern' input | xargs -I% cp "%" "%.bac"

#2


4  

You can use $() to interpolate the output of a command. So, you could use kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }')) if you wanted to.

您可以使用$()来插入命令的输出。所以,你可以使用kill -9 $(grep -hP'^ \ d + $'$(ls -lad / dir / * / pid | grep -P'/ dir / \ d + / pid'| awk'{print $ 9} '))如果你想。

#3


3  

In addition to Chris Jester-Young good answer, I would say that xargs is also a good solution for these situations:

除了Chris Jester-Young的好答案之外,我想说xargs对于这些情况也是一个很好的解决方案:

grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9

will make it. All together:

会做到的。全部一起:

grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9

#4


1  

For completeness, I'll also mention command substitution and explain why this is not recommended:

为了完整起见,我还会提到命令替换并解释为什么不建议这样做:

cp $(grep -l "pattern" input) directory/

(The backtick syntax cp `grep -l "pattern" input` directory/ is roughly equivalent, but it is obsolete and unwieldy; don't use that.)

(反引号语法cp`grep -l“模式”输入“目录/大致相同,但它过时且不实用;不要使用它。)

This will fail if the output from grep produces a file name which contains whitespace or a shell metacharacter.

如果grep的输出产生包含空格或shell元字符的文件名,则会失败。

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.

当然,如果您确切地知道grep可以生成哪些文件名,并且已经验证它们都没有问题,那么可以使用它。但是对于生产脚本,请不要使用它。

Anyway, for the OP's scenario, where you need to refer to each match individually and add an extension to it, the xargs or while read alternatives are superior anyway.

无论如何,对于OP的场景,你需要单独引用每个匹配并为其添加扩展,无论如何,xargs或while读取替代方案都是优越的。

In the worst case (meaning problematic or unspecified file names), pass the matches to a subshell via xargs:

在最坏的情况下(意味着有问题或未指定的文件名),通过xargs将匹配传递给子shell:

grep -l "pattern" input |
xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _

... where obviously the script inside the for loop could be arbitrarily complex.

...显然,for循环中的脚本可能是任意复杂的。

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 of xargs (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):

在理想情况下,您要运行的命令足够简单(或通用),您可以简单地将其传递给任意长的文件名列表。例如,GNU cp有一个-t选项来促进xargs的使用(-t选项允许你将目标目录放在命令行的第一位,这样你就可以在命令的末尾放置任意数量的文件):

grep -l "pattern" input | xargs cp -t destdir

which will expand into

这将扩展到

cp -t destdir file1 file2 file3 file4 ...

for as many matches as xargs can fit onto the command line of cp, repeated as many times as it takes to pass all the files to cp. (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 per cp invocation: the source file name and the destination file name to copy it to.)

因为xargs可以匹配到cp的命令行,所以需要多次重复将所有文件传递给cp所需的次数。 (不幸的是,这与OP的情况不匹配;如果您需要在复制时重命名每个文件,则每个cp调用只需要传入两个参数:源文件名和目标文件名以将其复制到。)

So in other words, if you use the command substitution syntax and grep produces a really long list of matches, you risk bumping into ARG_MAX and "Argument list too long" errors; but xargs will specifically avoid this by instead copying only as many arguments as it can safely pass to cp at a time, and running cp multiple times if necessary instead.

换句话说,如果你使用命令替换语法并且grep产生了很长的匹配列表,你就有可能碰到ARG_MAX和“Argument list too long”错误;但xargs会特别避免这种情况,而只是复制尽可能多的参数,因为它一次可以安全地传递给cp,并在必要时多次运行cp。

#1


12  

You can use xargs:

你可以使用xargs:

grep 'pattern' input | xargs -I% cp "%" "%.bac"

#2


4  

You can use $() to interpolate the output of a command. So, you could use kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }')) if you wanted to.

您可以使用$()来插入命令的输出。所以,你可以使用kill -9 $(grep -hP'^ \ d + $'$(ls -lad / dir / * / pid | grep -P'/ dir / \ d + / pid'| awk'{print $ 9} '))如果你想。

#3


3  

In addition to Chris Jester-Young good answer, I would say that xargs is also a good solution for these situations:

除了Chris Jester-Young的好答案之外,我想说xargs对于这些情况也是一个很好的解决方案:

grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9

will make it. All together:

会做到的。全部一起:

grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9

#4


1  

For completeness, I'll also mention command substitution and explain why this is not recommended:

为了完整起见,我还会提到命令替换并解释为什么不建议这样做:

cp $(grep -l "pattern" input) directory/

(The backtick syntax cp `grep -l "pattern" input` directory/ is roughly equivalent, but it is obsolete and unwieldy; don't use that.)

(反引号语法cp`grep -l“模式”输入“目录/大致相同,但它过时且不实用;不要使用它。)

This will fail if the output from grep produces a file name which contains whitespace or a shell metacharacter.

如果grep的输出产生包含空格或shell元字符的文件名,则会失败。

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.

当然,如果您确切地知道grep可以生成哪些文件名,并且已经验证它们都没有问题,那么可以使用它。但是对于生产脚本,请不要使用它。

Anyway, for the OP's scenario, where you need to refer to each match individually and add an extension to it, the xargs or while read alternatives are superior anyway.

无论如何,对于OP的场景,你需要单独引用每个匹配并为其添加扩展,无论如何,xargs或while读取替代方案都是优越的。

In the worst case (meaning problematic or unspecified file names), pass the matches to a subshell via xargs:

在最坏的情况下(意味着有问题或未指定的文件名),通过xargs将匹配传递给子shell:

grep -l "pattern" input |
xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _

... where obviously the script inside the for loop could be arbitrarily complex.

...显然,for循环中的脚本可能是任意复杂的。

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 of xargs (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):

在理想情况下,您要运行的命令足够简单(或通用),您可以简单地将其传递给任意长的文件名列表。例如,GNU cp有一个-t选项来促进xargs的使用(-t选项允许你将目标目录放在命令行的第一位,这样你就可以在命令的末尾放置任意数量的文件):

grep -l "pattern" input | xargs cp -t destdir

which will expand into

这将扩展到

cp -t destdir file1 file2 file3 file4 ...

for as many matches as xargs can fit onto the command line of cp, repeated as many times as it takes to pass all the files to cp. (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 per cp invocation: the source file name and the destination file name to copy it to.)

因为xargs可以匹配到cp的命令行,所以需要多次重复将所有文件传递给cp所需的次数。 (不幸的是,这与OP的情况不匹配;如果您需要在复制时重命名每个文件,则每个cp调用只需要传入两个参数:源文件名和目标文件名以将其复制到。)

So in other words, if you use the command substitution syntax and grep produces a really long list of matches, you risk bumping into ARG_MAX and "Argument list too long" errors; but xargs will specifically avoid this by instead copying only as many arguments as it can safely pass to cp at a time, and running cp multiple times if necessary instead.

换句话说,如果你使用命令替换语法并且grep产生了很长的匹配列表,你就有可能碰到ARG_MAX和“Argument list too long”错误;但xargs会特别避免这种情况,而只是复制尽可能多的参数,因为它一次可以安全地传递给cp,并在必要时多次运行cp。