我应该使用什么方法在 bash 脚本中使用“printf”将错误消息写入“stderr”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10963653/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:27:55  来源:igfitidea点击:

What method should I use to write error messages to 'stderr' using 'printf' in a bash script?

bashstderrio-redirectionbash4

提问by irrational John

I want to direct the output of a printfin a bashscript to stderrinstead of stdout.

我想将脚本printf中 a的输出定向bashstderr而不是stdout.

I am notasking about redirecting either stderror stdoutfrom where ever they are currently routed. I just want to be able to send the output from a printfto stderrinstead of to the default of stdout.

不是在询问重定向stderrstdout从它们当前路由的位置进行重定向。我只是希望能够将输出从 a 发送printfstderr而不是发送到默认的stdout.

I experimented a little and found that appending 1>&2to the printf, as shown in the example below, appears to do what I want. However, I have noexperience using bash. So my primaryquestion is if there is a "better" way to do this in bash?

我进行了一些试验,发现附加1>&2printf,如下面的示例所示,似乎可以满足我的要求。但是,我没有使用 bash 的经验。所以我的主要问题是是否有“更好”的方法来做到这一点bash

By "better" I mean is there another way to do this which is more commonly used, more conventional, or more idiomatic? How would a more experienced bash programmer do it?

更好”我的意思是有没有另一种更常用、更传统或更惯用的方法来做到这一点?更有经验的 bash 程序员会怎么做?

#!/bin/bash
printf "{%s}   This should go to stderr.\n" "$(date)" 1>&2 
printf "[(%s)] This should go to stdout.\n" "$(date)" 

I also have a secondaryquestion. I am asking it not so much because I needto know, but more because I am just curious and would like to have a better understanding about what is happening.

我还有一个次要问题。我问它不是因为我需要知道,而是更多是因为我只是好奇并且想更好地了解正在发生的事情。

It seems the above will only work when it runs inside a shell script. It does not appear to work when I try it from a command line.

上面的内容似乎只有在 shell 脚本中运行时才有效。当我从命令行尝试它时,它似乎不起作用。

Here is an example of what I mean.

这是我的意思的一个例子。

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

I would expect the printfcommand above to have no output because the output should go to stderr, which in turn should go to a file. But this does not happen. Huh?

我希望printf上面的命令没有输出,因为输出应该转到stderr,而后者又应该转到一个文件。但这不会发生。嗯?

回答by hobbs

First, yes, 1>&2is the right thing to do.

首先,是的,这1>&2是正确的做法。

Second, the reason your 1>&2 2>errors.txtexample doesn't work is because of the details of exactly what redirection does.

其次,您的1>&2 2>errors.txt示例不起作用的原因是重定向的具体细节。

1>&2means "make filehandle 1 point to wherever filehandle 2 does currently" — i.e. stuff that would have been written to stdout now goes to stderr. 2>errors.txtmeans "open a filehandle to errors.txtand make filehandle 2 point to it" — i.e. stuff that would have been written to stderr now goes into errors.txt. But filehandle 1 isn't affected at all, so stuff written to stdout still goes to stderr.

1>&2意思是“让文件句柄 1 指向文件句柄 2 当前所做的任何地方”——也就是说,本来应该写到 stdout 的东西现在转到了 stderr。2>errors.txt意思是“打开一个文件句柄errors.txt并使文件句柄 2 指向它”——也就是说,本来应该写入 stderr 的东西现在进入errors.txt. 但是文件句柄 1 根本不受影响,因此写入 stdout 的内容仍会进入 stderr。

The correct thing to do is 2>errors.txt 1>&2, which will make writes to both stderr and stdout go to errors.txt, because the first operation will be "open errors.txtand make stderr point to it", and the second operation will be "make stdout point to where stderr is pointing now".

正确的做法是2>errors.txt 1>&2,这将使对 stderr 和 stdout 的写入都转到errors.txt,因为第一个操作将是“打开errors.txt并使 stderr 指向它”,第二个操作将是“使 stdout 指向 stderr 指向的位置”现在”。

回答by Carl Norum

  1. That seems reasonable to me. You don't need the 1, though - it will work as is, but it's implied:

    printf "{%s}   This should go to stderr.\n" "$(date)" >&2 
    
  2. You have an order-of-operations problem:

    $ 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.
    
  1. 这对我来说似乎是合理的。您不需要1,虽然 - 它会按原样工作,但它暗示:

    printf "{%s}   This should go to stderr.\n" "$(date)" >&2 
    
  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.
    

回答by Todd A. Jacobs

The typical idioms are:

典型的成语是:

echo foo >&2           # you don't need to specify file descriptor 1
echo foo > /dev/stderr # more explicit, but wordier and less portable

回答by Enrique Perez-Terron

The question seems to indicate some confusion. You don't want to redirect stdout, you just want to have printf send its output to stderr... But to to that, you must use redirection.

这个问题似乎表明了一些混乱。您不想重定向标准输出,您只想让 printf 将其输出发送到标准错误...但为此,您必须使用重定向。

The printf command always sends normal output to its stdout. That is what printf does. In order to achieve what you want, you have to have the shell arrange that stdout temporarily points to wherever you want the output to go. Notice that I say temporarily. When you type a command like

printf 命令始终将正常输出发送到其标准输出。这就是 printf 所做的。为了实现你想要的,你必须让 shell 安排 stdout 临时指向你想要输出去的任何地方。注意我说的是暂时的。当你输入一个命令时

$ printf "Hello World!" >&2

the shell modifies the stdout handle for the duration of the execution of the printf statement. Then the shell restores the original value of stdout before it continues with the next command. In fact, if you want to redirect stdout permanently, you use the special command

shell 在 printf 语句的执行期间修改 stdout 句柄。然后 shell 在继续执行下一个命令之前恢复 stdout 的原始值。事实上,如果你想永久重定向stdout,你可以使用特殊命令

$ exec >&2

After the shell has executed this, the shell no longer remembers the original value of the stdout handle.

在外壳执行此操作后,外壳不再记住标准输出句柄的原始值。