247

Bourne シェル スクリプトのすべての出力をどこかにリダイレクトすることは可能ですが、スクリプト自体の中にシェル コマンドを使用することはできますか?

1 つのコマンドの出力をリダイレクトするのは簡単ですが、次のようなものが必要です。

#!/bin/sh
if [ ! -t 0 ]; then
    # redirect all of my output to a file here
fi

# rest of script...

意味: スクリプトが非対話的に実行される場合 (たとえば、cron)、すべての出力をファイルに保存します。シェルから対話的に実行する場合は、出力を通常どおり stdout に送信します。

FreeBSD定期ユーティリティによって通常実行されるスクリプトに対してこれを実行したいと考えています。これは日常の一部であり、通常はメールで毎日見るのは気にしないので、送信していません。ただし、この特定のスクリプト内の何かが失敗した場合、それは私にとって重要であり、日常業務のこの部分の出力をキャプチャして電子メールで送信できるようにしたいと考えています.

更新: ジョシュアの答えは的を射ていますが、スクリプト全体で stdout と stderr を保存して復元したいと考えていました。これは次のように行われます。

# save stdout and stderr to file 
# descriptors 3 and 4, 
# then redirect them to "foo"
exec 3>&1 4>&2 >foo 2>&1

# ...

# restore stdout and stderr
exec 1>&3 2>&4
4

5 に答える 5

226

更新された質問に対処します。

#...part of script without redirection...

{
    #...part of script with redirection...
} > file1 2>file2 # ...and others as appropriate...

#...residue of script without redirection...

中かっこ '{ ... }' は、I/O リダイレクションの単位を提供します。中括弧は、コマンドが表示される可能性のある場所 (単純化すると、行の先頭またはセミコロンの後に表示される必要があります) に表示する必要があります。(はい、それはもっと正確にすることができます。もしあなたが言いたいことがあれば、私に知らせてください。 )

あなたが示したリダイレクトで元の stdout と stderr を保持できることは正しいですが、通常、後でスクリプトを維持する必要がある人々が、リダイレクトされたコードを上記のようにスコープすると、何が起こっているのかを理解するのが簡単になります。

Bash マニュアルの関連セクションはGrouping CommandsI/O Redirectionです。POSIX シェル仕様の関連セクションは、複合コマンドI/O リダイレクションです。Bash にはいくつかの追加の表記法がありますが、それ以外は POSIX シェル仕様に似ています。

于 2008-11-24T19:11:28.293 に答える
214

通常、これらのいずれかをスクリプトの上部またはその近くに配置します。コマンド ラインを解析するスクリプトは、解析後にリダイレクトを行います。

stdout をファイルに送信する

exec > file

標準エラーあり

exec > file                                                                      
exec 2>&1

stdout と stderr の両方をファイルに追加する

exec >> file
exec 2>&1

ジョナサン・レフラー が彼のコメントで述べたように:

exec2 つの別々のジョブがあります。1 つ目は、現在実行中のシェル (スクリプト) を新しいプログラムに置き換えることです。もう 1 つは、現在のシェルで I/O リダイレクトを変更することです。これは、 に引数がないことで区別されexecます。

于 2008-11-24T16:29:52.957 に答える
40

次のように、スクリプト全体を関数にすることができます。

main_function() {
  do_things_here
}

次に、スクリプトの最後に次のように記述します。

if [ -z $TERM ]; then
  # if not run via terminal, log everything into a log file
  main_function 2>&1 >> /var/log/my_uber_script.log
else
  # run via terminal, only output to screen
  main_function
fi

または、実行ごとにすべてをログファイルに記録し、次のようにして標準出力に出力することもできます。

# log everything, but also output to stdout
main_function 2>&1 | tee -a /var/log/my_uber_script.log
于 2008-11-24T16:44:54.783 に答える
9

元の stdout と stderr を保存するには、次を使用できます。

exec [fd number]<&1 
exec [fd number]<&2

たとえば、次のコードは "walla1" と "walla2" をログ ファイル ( a.txt) に、"walla3" を stdout に、"walla4" を stderr に出力します。

#!/bin/bash

exec 5<&1
exec 6<&2

exec 1> ~/a.txt 2>&1

echo "walla1"
echo "walla2" >&2
echo "walla3" >&5
echo "walla4" >&6
于 2015-04-15T20:46:25.300 に答える
4
[ -t <&0 ] || exec >> test.log
于 2012-06-27T12:47:37.757 に答える