tee
インタラクティブに実行された各コマンドを、各コマンドごとに1つずつ一連の別々のログファイルに出力したいと思います。これを行うには、次のスクリプトを作成しました。このスクリプトは、シェルの起動時に(最後に.bashrc
)実行する最後のスクリプトに設定されます。
date=$(date +%Y-%m-%d_%H-%M-%S)
randstr=$(cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 4)
dir=~/log/"${date}_${randstr}"
mkdir "$dir"
i=0
while :
do
read -e -p "user@host:$(pwd)\$ " cmd
eval "$cmd 2>&1 | tee \"${dir}/${i}-${cmd}\""
(( i++ ))
done
しかし、ここにはいくつかの問題があります。まず、改行文字に会うとすぐに読み取りを停止します。これがread
うまくいく方法だからです。私はこのような行動を望んでいません。私はそれが正確にシェルのように動作したいと思います。たとえば、文章を書いてls &&
押したときにReturn何かをする前に、より多くの入力を待ちます。
この目標をどのように達成できますか?シェルスクリプトでこれを達成することは可能/実行可能ですか?もっと伝統的なプログラミング言語を使うべきですか?bash
これを達成するにはパッチを適用する必要がありますか?
答え1
# teeshell
date=$(date +%Y-%m-%d_%H-%M-%S)
randstr=$(cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 4)
dir="$(echo ~/log/"${date}_${randstr}")"
mkdir "$dir"
# Redirect everything to tee and perl
exec 1> >(tee /dev/tty |
perl -pe '
sub reopen {
open(OUT,">'$dir'/".++$i);
select OUT;
$| = 1;
}
BEGIN {
`echo $$ > "'$dir'"/pid`;
reopen();
$SIG{HUP} = \&reopen;
}') 2>&1
# wait for perl to save the pid
while [ ! -f "$dir"/pid ] ; do
true
done
# Magic! Make perl save to a new file with a kill -HUP
PS1="[\$(kill -HUP `cat "$dir"/pid`)][\u@\h:\w]\$ "
ランニング:
. teeshell