stdout 및 stderr을 스크립트 내부에서 파일 및 터미널로 리디렉션하는 방법.
#!/bin/bash
LOG_FILE="/tmp/abc.log"
exec &> >(tee -a $LOG_FILE)
echo "Start"
echo "Hi" 1>&2
echo "End"
위의 스크립트를 찾았습니다. 하지만 이 스크립트는 bash에서만 작동합니다. sh 쉘을 사용하면 다음 오류가 발생합니다.
./abc.sh: 5: Syntax error: redirection unexpected (expecting word)
sh 및 bash 쉘과 함께 사용할 수 있는 스크립트를 원합니다.
답변1
예, &>
연산자 bash
(이제 에서도 지원되며 zsh
항상 에서와 동일한 기능을 zsh
가짐 )와 연산자 (현재 및 에서도 지원됨 )는 둘 다 연산자가 아닙니다. 따옴표가 없는 $LOG_FILE, 여기서는 분명히 분할+glob을 사용하여 zsh 구문으로 만들고 싶지 않습니다( 이런 방식이기는 하지만 분할+glob이 따옴표가 없는 확장에서 암시적으로 수행하지 않는 유일한 셸입니다 ).>&
csh
>(...)
ksh
zsh
bash
sh
zsh
exec >&1 > $LOG_FILE 2>&1
구문적으로는 sh
다음과 같이 할 수 있습니다.
#! /bin/sh -
LOG_FILE="/tmp/abc.log"
{
# your script here
} 2>&1 | tee -- "$LOG_FILE"
아니면 모든 것을 함수에 넣으세요:
#! /bin/sh -
LOG_FILE="/tmp/abc.log"
main() {
# your script here
}
main "$@" 2>&1 | tee -- "$LOG_FILE"
그럼에도 불구하고 이 접근 방식과 zsh
-style 접근 방식은 모두 표준 출력에서 열린 동일한 리소스에 오류 메시지를 인쇄하게 됩니다. 따라서 누군가가 이렇게 하면 비어 있고 your-script > out 2> err
정상적인 출력과 오류가 포함됩니다.err
out
출력 및 오류의 원래 대상이 보존되도록 하려면 다음을 수행할 수 있습니다.
{
{
main "$@" 3>&- | tee -a -- "$LOG_FILE" >&3 3>&-
} 2>&1 | tee -a -- "$LOG_FILE" >&2 3>&-
} 3> "$LOG_FILE" 3>&1
(검증되지 않은).
또한 보안 관점에서 볼 때 전역적으로 쓰기 가능한 디렉터리에 고정된 이름을 가진 파일을 사용하는 것은 /tmp
나쁜 습관 입니다. 다른 사용자가 동일한 이름의 악의적인 심볼릭 링크를 배치할 수 있으므로 해당 링크가 가리키는 지점을 덮어쓰게 될 수 있습니다. 문서.