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

发布于 2024-07-19 10:43:57 字数 426 浏览 8 评论 0原文

假设我有一个包含 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 输出,但看起来好像也是 stderr 。

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

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

say i have a directory with hi.txt and blah.txt and i execute the following command on a linux-ish command line

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

the output you will see is

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

i'd like to redirect the stderr output (say 'echo blah.txt' fails...), leaving only the output from the xargs -t command written to std out, but it looks as if it's stderr as well.

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

Is there a way to control it, to make it output to stdout?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

城歌 2024-07-26 10:43:58

所以我相信您想要的是,因为 stdout 是

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

您想忽略由 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 移出
到标准输出。

% 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
%

So I believe what you want is to have as stdout is

  • the stdout from the utility that xargs executes
  • the listing of commands generated by xargs -t

You want to ignore the stderr stream generated by the
executed utility.

Please correct me if I'm wrong.

First, let's create a better testing utility:

% 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
%

So now we have something that actually outputs to both stdout and stderr, so we
can be sure we're only getting what we want.

A tangential way to do this is not to use xargs, but rather, make. Echoing a command
and then doing it is kind of what make does. That's its bag.

% 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
% 

If you're tied to using xargs, then you need to modify your utility that
xargs uses so it surpresses stderr. Then you can use the 2>&1 trick others
have mentioned to move the command listing generated by xargs -t from stderr
to 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
%

So this approach works, and collapses everything you want to stdout (leaving out what you don't want).

If you find yourself doing this a lot, you can write a general utility to surpress 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
%
魂归处 2024-07-26 10:43:58

xargs -t 在执行之前将要执行的命令回显到 stderr。 如果您希望它们回显到 stderr,您可以使用 2>&1 结构将 stderr 通过管道传输到 stdout:

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

xargs -t echos the commands to be executed to stderr before executing them. If you want them to instead echo to stderr, you can pipe stderr to stdout with the 2>&1 construct:

ls *.* | xargs -t -i{} echo {} 2>&1
冷默言语 2024-07-26 10:43:58

看起来 xargs -t 会转到 stderr,您对此无能为力。

你可以这样做:

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

以在命令运行时仅在终端上显示 stderr 数据,然后按照 grep -v Foo: stderr 的方式 grep 遍历 stderr.txt 以查看是否发生任何意外情况.txt

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

It looks like xargs -t goes to stderr, and there's not much you can do about it.

You could do:

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

to display only the stderr data on your terminal as your command runs, and then grep through stderr.txt after to see if anything unexpected occurred, along the lines of grep -v Foo: stderr.txt

Also note that on Unix, ls *.* isn't how you display everything. If you want to see all the files, just run ls on its own.

海螺姑娘 2024-07-26 10:43:58

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

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

As I understand your problem using GNU Parallel http://www.gnu.org/software/parallel/ would do the right thing:

ls *.* | parallel -v echo {} 2> /dev/null
热血少△年 2024-07-26 10:43:57

使用:

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 没有提供将其自身的错误输出与其执行的命令的错误输出分开的规定,因此很难做到。

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

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

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

cat /tmp/new.script

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

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

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

Use:

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

The 2>&1 sends the standard error from xargs to where standard output is currently going; the >/dev/null sends the original standard output to /dev/null. So, the net result is that standard output contains the echo commands, and /dev/null contains the file names. We can debate about spaces in file names and whether it would be easier to use a sed script to put 'echo' at the front of each line (with no -t option), or whether you could use:

ls | xargs -i{} echo echo {}

(Tested: Solaris 10, Korn Shell ; should work on other shells and Unix platforms.)


If you don't mind seeing the inner workings of the commands, I did manage to segregate the error output from xargs and the error output of the command executed.

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

The (non-standard) command al lists its arguments one per line:

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

The first redirection (2>/tmp/xargs.stderr) sends the error output from xargs to the file /tmp/xargs.stderr. The command executed is 'ksh -c "ls -dl {} 2>&1"', which uses the Korn shell to run ls -ld on the file name with any error output going to standard output.

The output in /tmp/xargs.stderr looks like:

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

I used 'ls -ld' in place of echo to ensure I was testing errors - the files x1, x2, and xxx existed, but zzz does not.

The output on standard output looked like:

-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

When run without the command wrapped in 'ksh -c "..."', the I/O redirection was passed as an argument to the command ('ls -ld'), and it therefore reported that it could not find the file '2>&1'. That is, xargs did not itself use the shell to do the I/O redirection.

It would be possible to arrange for various other redirections, but the basic problem is that xargs makes no provision for separating its own error output from that of the commands it executes, so it is hard to do.

The other rather obvious option is to use xargs to write a shell script, and then have the shell execute it. This is the option I showed before:

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

You can then see the commands with:

cat /tmp/new.script

You can run the commands to discard the errors with:

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

And, if you don't want to see the standard output from the commands either, append 1>&2 to the end of the command.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文