tee
대화형으로 실행된 각 명령을 각 명령마다 하나씩 일련의 별도 로그 파일에 출력하고 싶습니다 . 이를 위해 다음 스크립트를 작성했습니다. 이 스크립트는 셸이 시작될 때(끝 .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