1

假设我有一个包含 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

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

4

5 回答 5

3

采用:

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

2>&1标准错误从xargs标准输出发送到当前的位置;将>/dev/null原始标准输出发送到/dev/null. 因此,最终结果是标准输出包含回显命令,并/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 shellls -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没有规定将自己的错误输出与其执行的命令分开,因此很难做到。

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

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

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

cat /tmp/new.script

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

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

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

于 2009-05-09T01:28:54.147 回答
2

所以我相信你想要的是标准输出

  • xargs 执行的实用程序的标准输出
  • 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。回应一个命令然后执行它就是 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其他人提到的技巧将 xargs -t 生成的命令列表从 stderr 移动到 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
%

因此,这种方法有效,并将您想要标准输出的所有内容折叠起来(省略您不想要的内容)。

如果您发现自己经常这样做,您可以编写一个通用实用程序来抑制 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
%
于 2009-05-09T03:16:29.580 回答
1

看起来 xargs -t 进入了标准错误,您对此无能为力。

你可以这样做:

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

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

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

于 2009-05-09T01:05:54.887 回答
1

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

ls *.* | xargs -t -i{} echo {} 2>&1
于 2009-05-09T01:06:45.510 回答
0

据我了解,您使用 GNU Parallel http://www.gnu.org/software/parallel/会做正确的事情:

ls *.* | parallel -v echo {} 2> /dev/null
于 2010-06-10T19:39:14.340 回答