我想将bash
脚本中printf
的输出定向到stderr
而不是stdout
。
我不是在询问重定向stderr
或stdout
它们当前路由的位置。我只是希望能够将输出从printf
发送到stderr
而不是默认的stdout
。
我做了一些实验,发现将1>&2
附加到printf
,如下例所示,似乎可以做我想做的事。但是,我没有使用 bash 的经验。所以我的主要问题是是否有"更好"的方法在bash
中做到这一点?
我所说的"更好"是指有没有另一种方法可以做到这一点,它更常用、更传统或更惯用?一个更有经验的bash程序员会怎么做?
#!/bin/bash
printf "{%s} This should go to stderr.n" "$(date)" 1>&2
printf "[(%s)] This should go to stdout.n" "$(date)"
我还有一个次要问题。我问它不是因为我需要知道,而是因为我只是好奇,想更好地了解正在发生的事情。
似乎上述内容只有在 shell 脚本中运行时才能工作。当我从命令行尝试它时,它似乎不起作用。
这是我的意思的一个例子。
irrational@VBx64:~$ printf "{%s} Sent to stderr.n" "$(date)" 1>&2 2> errors.txt
{Sat Jun 9 14:08:46 EDT 2012} Sent to stderr.
irrational@VBx64:~$ ls -l errors.txt
-rw-rw-r-- 1 irrational irrational 0 Jun 9 14:39 errors.txt
我希望上面的printf
命令没有输出,因为输出应该转到stderr
,而又应该转到文件。但这不会发生。哼?
首先,是的,1>&2
是正确的做法。
其次,您的1>&2 2>errors.txt
示例不起作用的原因是因为重定向的确切细节
1>&2
的意思是"让FileHandle 1指向FileHandle 2当前所做的任何地方"——也就是说,本来应该写到stdout的东西现在变成了stderr。 2>errors.txt
的意思是"打开一个文件句柄来errors.txt
并使文件句柄 2 指向它"——也就是说,本来应该写到 stderr 的东西现在变成了errors.txt
。但是文件句柄 1 根本不受影响,所以写到 stdout 的东西仍然会转到 stderr。
正确的做法是2>errors.txt 1>&2
,这将使对stderr和stdout的写入都转到errors.txt
,因为第一个操作将是"打开errors.txt
并使stderr指向它",第二个操作将是"使stdout指向stderr现在指向的位置"。
-
这在我看来是合理的。 不过,您不需要
1
- 它将按原样工作,但它是隐含的:printf "{%s} This should go to stderr.n" "$(date)" >&2
-
您有一个操作顺序问题:
$ printf "{%s} Sent to stderr.n" "$(date)" 2> errors.txt 1>&2 $ ls -l errors.txt -rw-r--r-- 1 carl staff 47 Jun 9 11:51 errors.txt $ cat errors.txt {Sat Jun 9 11:51:48 PDT 2012} Sent to stderr.
典型的习语是:
echo foo >&2 # you don't need to specify file descriptor 1
echo foo > /dev/stderr # more explicit, but wordier and less portable
这个问题似乎表明了一些混乱。您不想重定向标准输出,您只想让 printf 将其输出发送到标准输出...但要做到这一点,您必须使用重定向。
printf 命令始终将正常输出发送到其标准输出。这就是printf所做的。为了实现你想要的,你必须让 shell 排列,让 stdout 暂时指向你想要输出去的地方。请注意,我说的是暂时的。当您键入类似命令时
$ printf "Hello World!" >&2
命令行管理程序在执行 printf 语句期间修改 stdout 句柄。然后,shell 在继续执行下一个命令之前恢复 stdout 的原始值。实际上,如果要永久重定向stdout,请使用特殊命令
$ exec >&2
外壳执行完此操作后,外壳不再记住标准输出句柄的原始值。