
次のようにスクリプト内からスクリプトの出力をログファイルにリダイレクトできますexec
。
#!/bin/bash
exec > stdout.log 2>&1
echo hello world
less
ファイルの代わりに出力をリダイレクトすることは可能ですか?試してみました
#!/bin/bash
exec > >(less) 2>&1
# output some text
for (( i=1; i <= 500; i++ )); do echo "hello world $i"; done
しかし、これは奇妙な方法で失敗します...プロンプトは表示されませんが、ターミナルに戻ります。
これをスクリプトの先頭に設定したいと思います (引数、tty などに応じて条件付きにできるようにします)。
答え1
スクリプトはless
子プロセスを待機する必要があります。そうしないと、スクリプトが子プロセスの前に終了し、less
突然フォアグラウンド プロセス グループから外れてしまい、ターミナルからコマンドを読み取ったり、ターミナル設定を復元したりできなくなります。
less
また、入力の終了を永久に待機することを防ぐために、スクリプトは入力へのパイプを閉じる必要があります。
これらすべてをまとめると次のようになります。
exec > >(less) 2>&1
trap 'exec >&- 2>&-; wait' EXIT
# >&- 2>&- => close stdout and stderr => cause EOF on less' stdin
seq 1 50000
# the rest of your script
しかし、これはあまり良くなく、他のほとんどのシェルに移植できず、文書化されていない (信頼できない) bash の動作に依存しています。スクリプトにwait
が複数ある場合exec > >(...)
、 は正常に動作せず、 で開始された他のバックグラウンド プロセスも待機することになります&
。
より良いアイデアとしては、無限再帰を避けるために環境変数を使用してスクリプト自身を呼び出すことです。
if [ ! "$CALLED_MYSELF" ]; then
set -o pipefail # supported in bash, but not in all the shells
CALLED_MYSELF=1 "$0" "$@" 2>&1 | less
exit
fi
seq 1 50000
# the rest of your script
答え2
次のように試してください (行なしexec
):
for (( i=1; i <= 500; i++ )); do echo "hello world $i"; done | less
(アップデート)
スクリプト全体を含める場合は、スクリプトを次のようにラップします。{ ... }
#!/bin/bash
{
# output some text
for (( i=1; i <= 500; i++)) do echo "hello world $i"; done
# whatever output you want...
} | less