it-swarm.cn

每行管道输入执行一次命令?

我想为ls | grep pattern -的每一次匹配运行一次Java命令)。在这种情况下,我想我可以做find pattern -exec Java MyProg '{}' \;,但我对一般情况感到好奇-是否有一种简单的方式说“对标准输入的每一行运行一次命令”?(用fish或bash)。

176
Xodarap

xargs就是这样做的。

... | xargs command
98
Keith

接受的答案 有正确的想法,但关键是要传递xargs-n1开关,表示“每行输出执行一次命令:”

cat file... | xargs -n1 command

或者,对于单个输入文件,您可以完全避免使用cat的管道,而只需执行以下操作:

<file xargs -n1 command
193
Michael Goldshteyn

在Bash或任何其他Bourne样式的Shell中(ash,ksh,zsh等):

while read -r line; do command "$line"; done

read -r从标准输入(read不带-r解释反斜杠,您不希望这样)。因此,您可以执行以下任一操作:

$ command | while read -r line; do command "$line"; done  

$ while read -r line; do command "$line"; done <file
117
Steven D

我同意Keith的观点,xargs是最通用的工具。

我通常使用3个步骤。

  • 做一些基本的事情,直到您想使用一些东西为止
  • 用awk准备该行,以获取正确的语法
  • 然后让xargs也许在bash的帮助下执行它。

有更小更快的方法,但是这种方法几乎总是可行的。

一个简单的例子:

ls | 
grep xls | 
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' | 
xargs -0 bash -c

前两行选择了一些要使用的文件,然后awk用一个要执行的命令和一些参数准备了一个尼斯字符串,而$ 1是管道的第一列输入。最后,我确保xargs将此字符串发送给刚执行的bash。

这有点矫kill过正,但是由于它非常灵活,因此此食谱在很多地方都对我有所帮助。

22
Johan

GNU Parallel专为此类任务而设计。最简单的用法是:

cat stuff | grep pattern | parallel Java MyProg

观看介绍性视频以了解更多信息: http://www.youtube.com/watch?v=OpaiGYxkSuQ

15
Ole Tange

另外,while read在fish Shell中循环(考虑到您使用了 fish 标签,我假设您要使用Fish Shell)。

command | while read line
    command $line
end

需要注意的几点。

  • read不带-r参数,并且它不会解释您的反斜杠,以使最常见的用例变得容易。
  • 您不需要引用$line,与bash不同,fish不会通过空格分隔变量。
  • command本身就是语法错误(以捕获占位符参数的这种用法)。用real命令替换它。
10
Konrad Borowski

在处理潜在的未经过滤的输入时,我希望在运行它之前逐行查看整个作业的“拼写”以进行视觉检查(尤其是当它具有破坏性,如清理人们的邮箱时)。

所以我要做的是生成一个参数列表(即用户名),以每行一个记录的方式将其馈送到文件中,如下所示:

johndoe  
jamessmith  
janebrown  

然后,我在vim中打开列表,并使用搜索对其进行处理并替换表达式,直到获得需要执行的完整命令列表,如下所示:

/bin/rm -fr /home/johndoe  
/bin/rm -fr /home/jamessmith 

这样,如果您的正则表达式不完整,您将看到在哪个命令中可能会出现问题(即/bin/rm -fr johnnyo connor)。这样,您可以撤消正则表达式,然后使用更可靠的版本再次尝试。名称修改为此而臭名昭著,因为很难处理所有的Edge案件,例如Van Gogh,O'Connors,St。Clair,Smith-Wesson。

set hlsearch对于在vim中执行此操作很有用,因为它将突出显示所有匹配项,因此您可以轻松地发现它是否不匹配或以意外方式匹配。

一旦您的正则表达式是完美的并捕获了您可以测试/考虑的所有情况,那么我通常将其转换为sed表达式,以便可以完全自动化以进行另一次运行。

对于输入行数妨碍您进行外观检查的情况,我强烈建议在执行命令之前将命令回显到屏幕(或者更好的是日志),因此,如果出现错误,您可以确切地知道引起该命令的原因它失败了。然后,您可以返回到原始正则表达式并再次进行调整。

1
Marcin

在这里,您可以立即使用复制粘贴:

cat list.txt | xargs -I{} command parameter {} parameter

列表中的项目将放在{}所在的位置,其余命令和参数将按原样使用。

1
DustWolf

如其他答案所示,可以使用xargs。我们需要在问题的“每行一次”部分中区分两个细节:

  1. 一次:使用-n 1,这可以确保为每个参数精确地调用一次命令。但是,默认情况下,xargs假定参数以空格分隔-一旦文件包含空格,该参数就会中断。
  2. 每行:使用-d '\n'或使用tr '\n' '\0'预处理输入并使用-0。这使该命令对输入中的空格具有鲁棒性。

最终的命令行将变为:

.... | xargs -n 1 -d '\n' <command>

或(使用tr

.... | tr '\n' '\0' | xargs -n 1 -0 <command>

如果您的命令可以一次处理多个参数(例如grepsed),则可以省略-n 1以在许多情况下加快操作速度。

0
krlmlr

如果程序忽略管道,但接受文件作为参数,则可以将其指向特殊文件/dev/stdin

我对Java不熟悉,但是这里有一个示例,说明如何使用bash:

$ echo $'pwd \n cd / \n pwd' |bash /dev/stdin
/home/rolf
/

$是bash将\n转换为换行符所必需的。我不知道为什么。

0
Rolf

我更喜欢-允许多行命令和清除代码

find -type f -name filenam-pattern* | while read -r F
do
  echo $F
  cat $F | grep 'some text'
done

引用 https://stackoverflow.com/a/3891678/248616

0
Nam G VU