是`xargs -t`输出stderr或stdout,你能控制它吗?

时间:2009-05-09 00:44:52

标签: command-line xargs

说我有一个带hi.txt和blah.txt的目录,我在linux-ish命令行上执行以下命令

ls *.* | xargs -t -i{} echo {}

您将看到的输出是

echo blah.txt
blah.txt
echo hi.txt
hi.txt

我想重定向stderr输出(比如'echo blah.txt'失败...),只留下xargs -t命令的输出写入std out,但它看起来好像也是stderr。

ls *.* | xargs -t -i{} echo {} 2> /dev/null

有没有办法控制它,让它输出到stdout?

5 个答案:

答案 0 :(得分:3)

使用:

ls | xargs -t -i{} echo {} 2>&1 >/dev/null

2>&1将标准错误从xargs发送到标准输出当前的位置; >/dev/null将原始标准输出发送到/dev/null。因此,最终结果是标准输出包含echo命令,/dev/null包含文件名。我们可以讨论文件名中的空格以及是否更容易使用sed脚本将'echo'放在每行的前面(没有-t选项),或者是否可以使用:

ls | xargs -i{} echo echo {}

(已测试:Solaris 10,Korn Shell;应该适用于其他shell和Unix平台。)


如果您不介意查看命令的内部工作原理,我确实设法将xargs的错误输出与执行的命令的错误输出隔离开来。

al * zzz | xargs -t 2>/tmp/xargs.stderr -i{} ksh -c "ls -dl {} 2>&1"

(非标准)命令al每行列出一个参数:

for arg in "$@"; do echo "$arg"; done

第一次重定向(2>/tmp/xargs.stderr)将xargs的错误输出发送到文件/tmp/xargs.stderr。执行的命令是“ksh -c "ls -dl {} 2>&1"”,它使用Korn shell在文件名上运行ls -ld,并将任何错误输出转到标准输出。

/tmp/xargs.stderr中的输出如下:

ksh -c ls -dl x1 2>&1
ksh -c ls -dl x2 2>&1
ksh -c ls -dl xxx 2>&1
ksh -c ls -dl zzz 2>&1

我使用“ls -ld”代替echo以确保我测试错误 - 文件x1x2xxx已存在,但zzz没有。

标准输出的输出如下:

-rw-r--r--   1 jleffler rd          1020 May  9 13:05 x1
-rw-r--r--   1 jleffler rd          1069 May  9 13:07 x2
-rw-r--r--   1 jleffler rd            87 May  9 20:42 xxx
zzz: No such file or directory

在没有包含在'ksh -c "..."'中的命令的情况下运行时,I / O重定向作为参数传递给命令('ls -ld'),因此报告它无法找到文件“2>&1”。也就是说,xargs本身并没有使用shell来进行I / O重定向。

可以安排各种其他重定向,但基本问题是xargs没有规定将自己的错误输出与它执行的命令分开,因此很难做到。 / p>

另一个相当明显的选择是使用xargs编写shell脚本,然后让shell执行它。这是我之前展示的选项:

ls | xargs -i{} echo echo {} >/tmp/new.script

然后,您可以使用以下命令查看命令:

cat /tmp/new.script

您可以使用以下命令运行命令以丢弃错误:

sh /tmp/new.script 2>/dev/null

并且,如果您不想查看命令的标准输出,请将1>&2附加到命令的末尾。

答案 1 :(得分:2)

所以我相信你想要的是stdout

  • xargs执行的实用程序中的stdout
  • xargs -t
  • 生成的命令列表

您想忽略由...生成的stderr流 执行效用。

如果我错了,请纠正我。

首先,让我们创建一个更好的测试实用程序:

% cat myecho
#!/bin/sh
echo STDOUT $@
echo STDERR $@ 1>&2
% chmod +x myecho
% ./myecho hello world
STDOUT hello world
STDERR hello world
% ./myecho hello world >/dev/null
STDERR hello world
% ./myecho hello world 2>/dev/null
STDOUT hello world
%

所以现在我们有一些实际输出到stdout和stderr的东西,所以我们 可以肯定我们只是得到了我们想要的东西。

执行此操作的切线方法不是使用xargs,而是使用make。回应命令 然后这样做是有道理的。那是它的包。

% cat Makefile
all: $(shell ls *.*)

$(shell ls): .FORCE
  ./myecho $@ 2>/dev/null

.FORCE:
% make
./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./myecho hi.txt 2>/dev/null
STDOUT hi.txt
% make >/dev/null
% 

如果您使用xargs,那么您需要修改您的实用程序 xargs用它来压低stderr。然后你可以使用其他2>&1技巧 已经提到过从stderr移动xargs -t生成的命令列表 到stdout。

% cat myecho2
#!/bin/sh
./myecho $@ 2>/dev/null
% chmod +x myecho2
% ./myecho2 hello world
STDOUT hello world
% ls *.* | xargs -t -i{} ./myecho2 {} 2>&1
./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./myecho hi.txt 2>/dev/null
STDOUT hi.txt
% ls *.* | xargs -t -i{} ./myecho2 {} 2>&1 | tee >/dev/null
%

所以这种方法有效,并且会折叠你想要stdout的一切(忽略你不想要的东西)。

如果你发现自己做了很多,你可以编写一个通用实用程序来压制stderr:

% cat surpress_stderr
#!/bin/sh
$@ 2>/dev/null
% ./surpress_stderr ./myecho hello world
STDOUT hello world
% ls *.* | xargs -t -i{} ./surpress_stderr ./myecho {} 2>&1
./surpress_stderr ./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./surpress_stderr ./myecho hi.txt 2>/dev/null
STDOUT hi.txt
%

答案 2 :(得分:1)

看起来xargs -t会转到stderr,而且你无能为力。

你可以这样做:

ls | xargs -t -i{} echo "Foo: {}" >stderr.txt | tee stderr.txt

在命令运行时仅显示终端上的stderr数据,然后通过stderr.txt grep查看是否发生了意外情况,沿grep -v Foo: stderr.txt

另请注意,在Unix上,ls *.*不是您显示所有内容的方式。如果您想查看所有文件,只需自行运行ls

答案 3 :(得分:1)

xargs -t回显在执行之前要对stderr执行的命令。如果你希望它们回显到stderr,你可以使用2>&1构造将stderr传递给stdout:

ls *.* | xargs -t -i{} echo {} 2>&1

答案 4 :(得分:0)

据我所知,使用GNU Parallel http://www.gnu.org/software/parallel/的问题会做正确的事情:

ls *.* | parallel -v echo {} 2> /dev/null