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

Xod*_*rap 225 shell bash fish

我想为每个匹配运行一次 java 命令ls | grep pattern -。在这种情况下,我想我可以做,find pattern -exec java MyProg '{}' \;但我对一般情况很好奇 - 有没有一种简单的方法可以说“为每一行标准输入运行一次命令”?(在鱼或bash中。)

Mic*_*eyn 263

接受的答案看法是正确的,但关键是要传递xargs-n1开关,这意味着“在使用每个命令行最多1个说法”

cat file... | xargs -n1 command
Run Code Online (Sandbox Code Playgroud)

或者,对于单个输入文件,您可以cat完全避免使用管道,只需使用:

<file xargs -n1 command
Run Code Online (Sandbox Code Playgroud)

2020-08-05 更新:

我还想对用户 Jander 评论中的建议做出回应,尽管我现在将解释该评论包含一些错误信息,但该评论得到了大量支持。

不要急于推荐 的-L选项xargs,而不要提及其(所谓的)尾随空白功能可能导致的麻烦。在我看来,此开关使得弊大于利,并肯定是用来指,为的情况下拉伸-L 1同时作用于一个非空行。公平地说,手册页xargs确实详细说明了与switch一起使用的功能(即问题)-L

由于 Jander 在提到-L可能是草率的毫无戒心的 StackOverflow 观众寻求快速提示并且没有时间阅读手册页而不是接受评论和答案作为福音等乏味的事情时没有提到这些问题,我现在将展示我的理由为什么-L如果没有仔细了解它带来的所有行李,这是一个非常糟糕的建议。

为了说明我对 的蔑视-L,让我们考虑一个简单的输入文件,其中包含某人不小心输入的以下文本(可能是高中暑期实习生创建此数据文件作为他/她的培训的一部分,其窗口化文件名证明了这一点。如运气(业力?)会拥有它,您已被管理层选为新的托管人):

testdata.txt

1
2?
3
Run Code Online (Sandbox Code Playgroud)

由于包含数字的行2有一个空格字符(在前面代码中SYMBOL FOR SPACE的数字后显示为 Unicode字形2,以防您的浏览器的字体没有此字符的可视化表示),因此命令使用xargs -L1,如:

<testdata.txt xargs -L1 echo
Run Code Online (Sandbox Code Playgroud)

...,将产生以下(可能令人惊讶)输出:

1
2 3
Run Code Online (Sandbox Code Playgroud)

这是由以下事实引起的-L开关指示xargs随后的行追加到那些端用空白,行为,其可以仅在那些古怪的时刻,其中线不正确修剪尾随空白的影响所产生的输出-定时炸弹错误等待正确的输入文件来展示自己。

另一方面,使用, 而不是-n 1switch的相同命令会产生更可接受的输出:xargs-L 1

1
2?
3
Run Code Online (Sandbox Code Playgroud)

这还不是最糟糕的!该-L不像开关-n势力“可怕”-x的选项xargs才能生效。xargs如果遇到一个命令行,它认为对于运行它的环境来说太长,这会导致进程终止。

一个输入文件由多行和连续的尾随空格组成,根据-L开关的指示以及它-x在混合中使用称为 Agent 的化学试剂,xargs如果所有这些连接成一个超行超过xargs' ,则可能导致中途终止line 的定义对于命令行来说太长了。如果事情开始变得模糊,请考虑该行太长xargs基于为其运行的平台指定的最大长度确定的大小,并进一步偏移看似任意常数,如手册页中更详细的解释. 记住微积分中那些讨厌的不定积分及其任意常数并在测验或测试中失去一分,因为您忘记+ C在解决不定积分之后编写?好吧,这句话又回来了,如果添加-L到您方便的xargs工具包中,它会再次咬住您。

-n的值1,另一方面,将刚砍那些长行到(希望)小一口大小的一个行块和执行提供给命令xargs为它们中的每,一次一个,而不给予他们是否任何考虑是否以空格结尾。不再需要排长队,也不再xargs因为突然终止而在背后捅你一刀 - Et tu, Brute -x ?

关于 xargs 手册页中的措辞的可选 segue

我不知道为什么在整个手册页中都使用了含糊不清和非标准的空白xargs,而不是定义更好且含糊不清的选项,例如:

  • 空格,如果空格表示一个或多个ASCII 空格字符
  • 换行符以外的空格(如果这就是空格所暗示的)
  • 一组中的一个或多个不可打印的字符:{空格,水平制表符}(如果空格被用作这个可怕的二人组的同义词)

2021-06-15 更新:

用户@BjornW 询问如何xargs使用每输入运行一次命令而不仅仅是输入单词。(看,我确实阅读了评论,我只会责怪在 Covid 上回复所花费的七个月时间:P)。

本着原问题的精神,正如所问的,为了使我的答案适用于更多的用例,我想详细解决这个特定的场景。

考虑以下输入文件。它充满了在Real World ™ 中可能实际遇到的各种边缘情况(例如,前导/尾随空格、仅由空格组成的行、空行、以连字符开头的行[不应被解释为引入一个开关]等):

lines.txt

a1 a22 a333 a4444
b4444 b333 b22 b1
??c d e f g
?
hhh
ii jj kk?
?
???
-L and -x are the gruesome twosome
?
?
?
Run Code Online (Sandbox Code Playgroud)

在前面的输入文件中,Unicode 字符OPEN BOXU+2423 用于标记空行,UnicodeSYMBOL FOR SPACE用于前导和尾随空格,以使其更加突出。

假设我们想在输入的每一行上运行一个命令,作为一个整体,并作为单个参数传递给我们的命令,而不管内容(包括没有内容)。我们将使用xargs,如下所示(注意:printf将是我们的示例命令,并且%q格式说明符将用于将提供的参数括在撇号中,为清晰起见,当存在空格或参数为空字符串时 - 全部在,只有我们的hhh输入行被留下“毫发无损” %q,正如您将在输出中看到的那样,很快就会出现。如果存在任何不可打印的字符,它们也会被%q使用 POSIX$''引用语法转义]):

<lines.txt xargs -n1 -d'\n' printf -- 'Input line: %q\n'
Run Code Online (Sandbox Code Playgroud)

输出如下:

Input line: 'a1 a22 a333 a4444'
Input line: 'b4444 b333 b22 b1'
Input line: '   c d e f g'
Input line: ''
Input line: hhh
Input line: 'ii jj kk '
Input line: ''
Input line: '   '
Input line: '-L and -x are the gruesome twosome'
Input line: ''
Input line: ''
Input line: ''
Run Code Online (Sandbox Code Playgroud)

所以你有它。使用-d开关,我们可以指定xargs应该在我们的输入文件中查找的分隔符,以指示参数的结束位置和下一个参数的开始位置。通过将它设置为'\n'xargs本身足够智能以解释为C 风格的字符转义-d如其man页面上的开关描述中所述,我们可以使用xargs将整行输入作为参数转发给我们选择的命令,最少我们的努力。

我还想提一下,xargs可用于连接多行输入(有一个警告,我将在本段末尾详细说明),对于需要这种行为的极少数情况,并将它们作为单个参数转发给我们命令。这可以通过将传递给上述调用命令中的-nswitch的数字设置xargs为一个值来完成,该值指示应该合并到单个参数中的输入行数,并将其\n行尾作为流程的一部分删除. 不幸的是,这种新行剥离行为使上述xargs方法不适用于许多用例,因为指示一行结束和下一行开始的信息在此过程中丢失了。

  • 您如何访问 `command` 中的行? (11认同)
  • printf "foo bar\nbaz bat" | xargs -n1 echo whee 按单词而不是按行拆分 (4认同)
  • 同样令人感兴趣的是,如果`stdin` 为空,`xargs` ***不***运行的能力:`--no-run-if-empty` `-r`:如果标准输入不包含任何非空白,不要运行命令。通常,即使没有输入,命令也会运行一次。此选项是 GNU 扩展。 (2认同)

Ste*_*n D 130

在 Bash 或任何其他 Bourne 风格的 shell(ash、ksh、zsh 等)中:

while read -r line; do command "$line"; done
Run Code Online (Sandbox Code Playgroud)

read -r从标准输入中读取一行(read-r解释反斜杠,你不想要)。因此,您可以执行以下任一操作:

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

$ while read -r line; do command "$line"; done <file
Run Code Online (Sandbox Code Playgroud)

  • 当我尝试 `tail -f syslog | grep -e 东西 -e 东西| 读行时;做 echo $line; 完成`它没有用。它使用管道传输到`while` 循环的文件,只使用`tail -f`,只使用`grep`,但不使用两个管道。为 `grep` 提供 `--line-buffered` 选项使其工作 (9认同)

Kei*_*ith 120

这就是xargs它的作用。

... | xargs command
Run Code Online (Sandbox Code Playgroud)

  • 不完全的。`printf "foo bar\nbaz bat" | xargs echo whee` 将产生 `whee foo bar baz bat`。也许添加`-L`或`-n`选项? (38认同)
  • 如果您想查看使用 xargs 执行此操作的正确方法,请参阅下面的答案。 (15认同)
  • 例如,“对问题给出正确答案的具体情况”。:) (14认同)
  • @Jander 这个问题很笼统,所以我给出了通用工具。确实,您必须根据具体情况使用选项调整其行为。 (5认同)
  • ... | tr '\n' '\0' | xargs -0 (4认同)

Joh*_*han 25

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

我通常使用 3 步方法。

  • 做基本的事情,直到你有你想要的东西
  • 使用 awk 准备该行,以便获得正确的语法
  • 然后让 xargs 执行它,也许在 bash 的帮助下。

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

一个简单的例子:

ls | 
grep xls | 
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' | 
xargs -0 bash -c
Run Code Online (Sandbox Code Playgroud)

前 2 行选择一些要处理的文件,然后 awk 准备一个漂亮的字符串,其中包含要执行的命令和一些参数,$1 是来自管道的第一列输入。最后我确保 xargs 将此字符串发送到 bash 执行它。

这有点矫枉过正,但这个食谱在很多地方帮助了我,因为它非常灵活。

另请注意,您还可以执行xargs -0 -n1 bash -c(只需添加-n1Michael Goldshteyn 建议的标志)在每一行输出上执行命令。

  • 注意,`xargs -0` 使用空字节作为记录分隔符,所以你的 awk 打印语句应该是 `printf("MyJavaProg --args \"%s\"\0",$1)` (6认同)

Ole*_*nge 17

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

cat stuff | grep pattern | parallel java MyProg
Run Code Online (Sandbox Code Playgroud)

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

  • @EricRenouf http://oletange.blogspot.dk/2013/10/useless-use-of-cat.html (3认同)
  • 这里不需要 `cat`,因为 `grep` 可以直接读取文件 (2认同)

ccp*_*zza 13

如果您需要控制将输入参数插入命令行的确切位置,或者需要重复多次,则可以使用xargs -I{}.

示例#1

another_folder镜像当前目录中的子文件夹中创建一个空文件夹结构:

    ls -1d ./*/ | xargs -I{} mkdir another_folder/{}
Run Code Online (Sandbox Code Playgroud) 示例#2

对来自 stdin 的文件列表应用操作,在这种情况下,.html通过附加.bak扩展名来制作每个文件的副本:

    find . -iname "*.html" | xargs -I{} cp {} {}.bak
Run Code Online (Sandbox Code Playgroud)

xargsMacOS/BSD手册页

 -I replstr
         Execute utility for each input line, replacing one or more occurrences of
         replstr in up to replacements (or 5 if no -R flag is specified) arguments
         to utility with the entire line of input.  The resulting arguments, after
         replacement is done, will not be allowed to grow beyond 255 bytes; this is
         implemented by concatenating as much of the argument containing replstr as
         possible, to the constructed arguments to utility, up to 255 bytes.  The
         255 byte limit does not apply to arguments to utility which do not contain
         replstr, and furthermore, no replacement will be done on utility itself.
         Implies -x.
Run Code Online (Sandbox Code Playgroud)

Linuxxargs手册页

   -I replace-str
          Replace  occurrences of replace-str in the initial-
          arguments with names read from standard input.  Al?
          so,  unquoted  blanks do not terminate input items;
          instead the separator  is  the  newline  character.
          Implies -x and -L 1.
Run Code Online (Sandbox Code Playgroud)


Kon*_*ski 11

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

command | while read line
    command $line
end
Run Code Online (Sandbox Code Playgroud)

需要注意的几点。

  • read不接受-r参数,也不解释您的反斜杠,以便使最常见的用例变得简单。
  • 您不需要引用$line,因为与 bash 不同,fish 不会用空格分隔变量。
  • command本身就是一个语法错误(捕捉占位符参数的这种使用)。用真正的命令替换它。