私はbashシェルのロギング関数を自分で書こうとしています。私の目標は、コマンドの前にプレフィックスを付け、コマンドのstdoutとstderrを日付ログファイルに渡す機能を持つことです。現在私は以下を持っています:
logme()
{
FULL_COMMAND=$@
for EXE in ${FULL_COMMAND}
do
case $EXE in
nohup) continue;;
time) continue;;
esac
break
done
mkdir -p logs
LOGNAME=$(basename ${EXE})_$(date +%Y-%m-%d_%H:%M:%S)
echo $FULL_COMMAND > logs/${LOGNAME}.e.log
echo '============' >> logs/${LOGNAME}.e.log
$FULL_COMMAND > logs/${LOGNAME}.o.log 2>> logs/${LOGNAME}.e.log
}
これは単純なケースで動作するようです。ランニング:
$ touch file1.txt
$ touch file2.txt
$ touch file3.txt
$ logme ls -lh
2つの日付ファイルを含むログディレクトリを作成します。
$ more logs/ls_2017-05-08_16\:05\:36.e.log
ls -lh
============
$ more logs/ls_2017-05-08_16\:05\:36.o.log
total 6.5K
-rw-r--r-- 1 aholman compbio 0 May 8 16:05 file1.txt
-rw-r--r-- 1 aholman compbio 0 May 8 16:05 file2.txt
-rw-r--r-- 1 aholman compbio 0 May 8 16:05 file3.txt
drwxr-xr-x 2 aholman compbio 92 May 8 16:05 logs
ただし、コマンドにパイプを追加すると、必要に応じて機能しません。ロギングは最初のコマンドにグループ化されて表示され、logmeの出力がパイプされます。もちろん、logmeの目的はファイルに送信することであるため、出力はありません。
$ logme ls -lh | grep -v file2
$ more logs/ls_2017-05-08_16\:12\:15.e.log
ls -lh
============
$ more logs/ls_2017-05-08_16\:12\:15.o.log
total 6.5K
-rw-r--r-- 1 aholman compbio 0 May 8 16:05 file1.txt
-rw-r--r-- 1 aholman compbio 0 May 8 16:05 file2.txt
-rw-r--r-- 1 aholman compbio 0 May 8 16:05 file3.txt
drwxr-xr-x 2 aholman compbio 92 May 8 16:12 logs
コマンド全体がlogmeによって処理されるようにコマンド全体をグループ化する良い方法はありますか?
答え1
スクリプトがコマンドラインを表示する前に、シェルはこれを処理しています。処理後に残ったもの(パイプ前のコマンド)のみ渡します。これらの処理をバイパスするには、コマンド全体を引用する必要があります。
logme 'ls -lh | grep -v file2'
ところで、新しい質問がありました。コマンドは文字列にあるため、直接実行することはできません。 1つの方法はevalを使用することです。
eval "$FULL_COMMAND" > logs/${LOGNAME}.o.log 2>> logs/${LOGNAME}.e.log
ただし、evalは簡単に悪用される可能性があるため、慎重に使用する必要があります。http://mywiki.wooledge.org/BashFAQ/048