web-dev-qa-db-ja.com

bashスクリプトで「printf」を使用して「stderr」にエラーメッセージを書き込むには、どの方法を使用すればよいですか?

printfスクリプトのbashの出力をstderrではなくstdoutに転送したい。

私はnotが現在ルーティングされている場所からstderrまたはstdoutをリダイレクトすることについて質問しています。出力をデフォルトのprintfではなくstderrからstdoutに送信できるようにしたいだけです。

私は少し実験して、1>&2 to printfは、以下の例に示すように、私がやりたいように見えます。しかし、私はno bashの使用経験があります。だから私のprimary質問は、「better」方法があるかどうかですこれをbashで行いますか?

better」とは、これを行う別の方法があることを意味します。これは、より一般的に使用されている、より慣習的、またはより慣用的な方法ですか?経験豊富なbashプログラマはどのようにそれを行いますか?

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

また、secondary質問があります。私は知る必要があるので、それほど多くは求めていません。 。

上記はシェルスクリプト内で実行した場合にのみ機能するようです。コマンドラインから試しても動作しないようです。

これが私の意味の例です。

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に送られ、次にファイルに送られるからです。しかし、これは起こりません。え?

31
irrational John

まず、はい、1>&2は正しいことです。

第2に、1>&2 2>errors.txtの例が機能しない理由は、リダイレクトが正確に行うことの詳細にあります。

1>&2は、「ファイルハンドル1を、ファイルハンドル2が現在行っている場所を指すようにする」ことを意味します。つまり、stdoutに書き込まれるはずだったものがstderrに送られます。 2>errors.txtは、「errors.txtへのファイルハンドルを開いて、ファイルハンドル2がそれを指すようにする」ことを意味します。つまり、stderrに書き込まれるはずだったものがerrors.txtに入ります。しかし、ファイルハンドル1はまったく影響を受けないため、stdoutに書き込まれたものは引き続きstderrに送られます。

最初に行う操作は「2>errors.txt 1>&2を開いてstderrがポイントする」ため、stderrとstdoutの両方への書き込みがerrors.txtに行われるerrors.txtが適切です。 2番目の操作は、「stdoutが現在stderrが指している場所を指すようにする」です。

31
hobbs
  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.
    
11
Carl Norum

質問はいくつかの混乱を示しているようです。 stdoutをリダイレクトするのではなく、printfに出力をstderrに送信させたいだけですが、そのためにはリダイレクトを使用する必要があります。

Printfコマンドは常に通常の出力をstdoutに送信します。それがprintfが行うことです。あなたが望むものを達成するために、あなたはシェルがstdoutがあなたが出力を行きたいどこにでも一時的に指すように手配する必要があります。一時的に言うことに注意してください。次のようなコマンドを入力すると

$ printf "Hello World!" >&2

シェルは、printfステートメントの実行中にstdoutハンドルを変更します。次に、シェルは次のコマンドを続行する前にstdoutの元の値を復元します。実際、stdoutを永続的にリダイレクトしたい場合は、特別なコマンドを使用します

$ exec >&2

シェルがこれを実行した後、シェルはstdoutハンドルの元の値を記憶しなくなります。

典型的なイディオムは次のとおりです。

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