如何将命令输出作为多个参数传递给另一个命令
Posted
技术标签:
【中文标题】如何将命令输出作为多个参数传递给另一个命令【英文标题】:How to pass command output as multiple arguments to another command 【发布时间】:2016-01-30 15:13:22 【问题描述】:我想将命令的每个输出作为多个参数传递给第二个命令,例如:
grep "pattern" input
返回:
file1
file2
file3
我想复制这些输出,例如:
cp file1 file1.bac
cp file2 file2.bac
cp file3 file3.bac
我怎样才能一口气做到这一点?比如:
grep "pattern" input | cp $1 $1.bac
【问题讨论】:
使用命令xargs
。
我猜你的意思是 grep -l
... 或者 input
包含一个文件名列表,并且你想要 grep 其中的一个子集。
另见PIping not working with echo command
另见bash pwd and open with pipe not working,里面有非常详细的解释。
【参考方案1】:
你可以使用xargs
:
grep 'pattern' input | xargs -I% cp "%" "%.bac"
【讨论】:
【参考方案2】:您可以使用$()
插入命令的输出。所以,如果你愿意,你可以使用kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk ' print $9 '))
。
【讨论】:
【参考方案3】:除了Chris Jester-Young good answer,我想说xargs
对于这些情况也是一个很好的解决方案:
grep ... `ls -lad ... | awk ' print $9 '` | xargs kill -9
会成功的。一起来:
grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk ' print $9 '` | xargs kill -9
【讨论】:
【参考方案4】:为了完整起见,我还将提及命令替换并解释为什么不推荐这样做:
cp $(grep -l "pattern" input) directory/
(反引号语法cp `grep -l "pattern" input` directory/
大致相同,但它已过时且笨拙;不要使用它。)
如果 grep
的输出生成的文件名包含空格或 shell 元字符,这将失败。
当然,如果您确切地知道grep
可以生成哪些文件名,并且已验证它们都没有问题,则可以使用它。但对于生产脚本,不要使用它。
无论如何,对于 OP 的场景,您需要单独引用每个匹配项并为其添加扩展名,xargs
或 while read
替代方案无论如何都是优越的。
在最坏的情况下(意味着有问题或未指定的文件名),通过xargs
将匹配项传递给子shell:
grep -l "pattern" input |
xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _
...for
循环内的脚本显然可以任意复杂。
在理想情况下,您要运行的命令足够简单(或通用),您可以简单地向它传递任意长的文件名列表。例如,GNU cp
有一个 -t
选项来促进 xargs
的这种使用(-t
选项允许您将目标目录 first 放在命令行上,这样您就可以在命令末尾添加任意数量的文件):
grep -l "pattern" input | xargs cp -t destdir
这将扩展为
cp -t destdir file1 file2 file3 file4 ...
xargs
可以匹配到cp
的命令行,重复多次以将所有文件传递给cp
。 (不幸的是,这与 OP 的场景不匹配;如果您需要在复制时重命名每个文件,则每次 cp
调用只需传入两个参数:源文件名和将其复制到的目标文件名。 )
换句话说,如果您使用命令替换语法并且grep
生成了一个非常 长的匹配列表,您可能会遇到ARG_MAX
和“Argument list too long”错误;但是xargs
会特别避免这种情况,而是一次只复制可以安全传递给cp
的尽可能多的参数,并在必要时多次运行cp
。
【讨论】:
【参考方案5】:#!/bin/bash
for f in files; do
if grep -q PATTERN "$f"; then
echo cp -v "$f" "$f.bac"
fi
done
文件可以是 *.txt 或 *.text ,这基本上意味着文件以 *.txt 或 *text 结尾或替换为您想要/需要的东西,当然用您的替换 PATTERN。如果您对输出感到满意,请删除 echo。对于递归解决方案,请查看 bash shell 选项 globstar
【讨论】:
以上是关于如何将命令输出作为多个参数传递给另一个命令的主要内容,如果未能解决你的问题,请参考以下文章
如何将数组的值作为第二个参数传递给 awk 的 split 函数?