使用xargs输出混淆

时间:2009-08-26 15:31:53

标签: unix command-line xargs

我将这些文件放在目录中:y y1 y2 y3

运行此命令:
ls y* | xargs -i basename {}|xargs -i sed "s/{}//g"

产生这个:
1
2
3

有人可以解释原因吗?!我希望它什么都不产生 - 运行sed四次,每个文件一次,并且每次都删除文件名。但实际上看起来它正在将sed与{}设置应用于第一个文件,在y1 y2 y3的列表上

这是Solaris 10

2 个答案:

答案 0 :(得分:2)

xargs -i sed ...命令的输入是:

y
y1
y2
y3

该命令将读取行y并执行sed s/y//g,它从标准输入读取。标准输入是继承的,因此它将具有与其标准输入相同的管道,并且可能能够读取剩余的输入:

y1
y2
y3

命令sed s/y//g将从每行删除y

1
2
3

但是,如果xargs在执行第一个sed命令之前消耗所有输入,那么sed命令将没有剩余的输入来读取,并且什么都不做。

答案 1 :(得分:2)

当我在我的linux盒子上尝试这个时,我得到的结果不一致。有时123,有时(大多数时间)23,有时12。这是最右边的xargs和它产生的任何sed之间的一种微妙的缓冲竞争条件。

解析命令行:

  • ls y*将输出4行y,y1,y2和y3;缓冲不相关
  • xargs -i basename {}会读取它们并按顺序启动basename ybasename y1basename y2basename y3;输出与我们的输入相同,是行缓冲的,因为每一行来自不同的进程。
  • xargs -i sed "s/{}//g",对于它读取的每一行X(稍后会详细介绍),启动sed "s/X//g"
  • 每个sed "s/X//g"过滤掉它在其读取的行中看到的每个X

它变得棘手:最后两个命令从同一个流中读取输入。该流由序列中的多个不同过程产生。根据多种因素(系统负载,调度),输出可能会以非常不同的时序模式出现。

让我们假设他们都非常快。然后,右侧xargs可以在单个块中读取所有四行。在这种情况下,任何sed s都没有输入,因此根本没有输出

另一方面,如果它们非常慢,则在第一次读取尝试时,右侧xargs可能只有一行可用。那条线将是“y”。 xargs会将第一个sed生成为sed "s/y//g",这将消耗所有剩余输入(y1,y2,y3),条带y输出1 ,2,3,。这是相同的解释,更明确的排序。

  1. 首先basename写“y”。
  2. xargs读“y”,产生sed s/y//gxargs现在等待sed完成。
  3. second basename写“y1”; sed读取“y1”,写入“1”
  4. 第三个basename写“y2”; sed读取“y2”,写入“2”
  5. 第四个basename写“y3”; sed读取“y3”,写入“3”
  6. xargs已完成; sed读取EOF并停止
  7. xargs尝试继续,读取EOF并停止
  8. 对我的12个案例不确定。可能GNU xargs在读取后续可用输入之前不等待其子项完成,并从第一个sed中抢夺了“y3”行。

    在任何情况下,您只需在同一作者上设置一个多个并发读者的管道,这会产生大多数不确定的结果。 要避免。

    如果您希望对每个文件进行操作,可以通过指定sed使用的文件名来避免(注意最终的{}):

    ls y* | xargs -i basename {} | xargs -i sed "s/{}//g" {}
    

    如果您想要的是跨产品类型的结果(从每个文件中删除每个文件名),您需要安排生成文件列表的次数与文件一样多。如果您仍然使用它,请加xargs一个。

    希望这有帮助。