func() {
echo 'hello'
echo 'This is an error' >&2
}
a=$(func)
b=???
b
임시 파일을 생성하지 않고 stderr를 변수 로 리디렉션하고 싶습니다 .
echo $b
# output should be: "This is an error"
작동하지만 임시 파일을 사용하는 솔루션:
touch temp.txt
exec 3< temp.txt
a=$(func 2> temp.txt);
cat <&3
rm temp.txt
문제는 어떻게 stderr
리디렉션 합니까?세게 때리다임시 파일 없이 func
변수에 기능을 적용하나요 ?b
답변1
zsh
쓰기 가능한 임시 파일을 사용하여 Linux 및 여기에 있는 문서(예: 5.1 또는 5.1 이전) 를 구현하는 셸에서 bash
다음을 수행할 수 있습니다.
{
out=$(
chmod u+w /dev/fd/3 && # needed for bash5.0
ls /dev/null /x 2> /dev/fd/3
)
status=$?
err=$(cat<&3)
} 3<<EOF
EOF
printf '%s=<%s>\n' out "$out" err "$err" status "$status"
( ls /dev/null /x
stdout 및 stderr에 무언가를 인쇄하는 예제 명령은 어디에 있습니까?)
를 사용하면 zsh
다음 작업도 수행할 수 있습니다.
(){ out=$(ls /dev/null /x 2> $1) status=$? err=$(<$1);} =(:)
( =(cmd)
임시 파일과 익명 함수를 사용한 프로세스 교체 형식입니다 (){ code; } args
.)
어쨌든 임시 파일을 사용하고 싶을 것입니다. 파이프를 사용하는 모든 솔루션은 출력이 크면 교착 상태가 발생하기 쉽습니다. 두 개의 개별 파이프를 통해 stdout 및 stderr을 읽고 루프에서 select()
/ poll()
및 일부 읽기를 사용하여 잠금을 발생시키지 않고 두 파이프에서 데이터를 읽을 수 있지만 이는 매우 복잡하며 AFAIK는 zsh
내장 select()
지원만 가능하고 yash
원시 인터페이스는 하나만 있습니다. pipe()
(자세한 내용은 참조쉘 리디렉션을 사용하여 동일한 파일 설명자 읽기/쓰기).
또 다른 접근 방식은 스트림 중 하나를 임시 파일 대신 임시 메모리에 저장하는 것입니다. 다음과 같습니다( zsh
또는 bash
구문):
{
IFS= read -rd '' err
IFS= read -rd '' out
IFS= read -rd '' status
} < <({ out=$(ls /dev/null /x); } 2>&1; printf '\0%s' "$out" "$?")
(명령이 NUL을 출력하지 않는다고 가정)
여기에는 $err
후행 줄바꿈이 포함됩니다.
다른 접근 방식은 stdout과 stderr을 다르게 장식하고 읽을 때 장식을 제거하는 것입니다.
out= err= status=
while IFS= read -r line; do
case $line in
(out:*) out=$out${line#out:}$'\n';;
(err:*) err=$err${line#err:}$'\n';;
(status:*) status=${line#status:};;
esac
done < <(
{
{
ls /dev/null /x |
grep --label=out --line-buffered -H '^' >&3
echo >&3 "status:${PIPESTATUS[0]}" # $pipestatus[1] in zsh
} 2>&1 |
grep --label=err --line-buffered -H '^'
} 3>&1
)
GNU grep
와 줄이 충분히 짧다고 가정합니다. 라인이 PIPEBUF(Linux의 경우 4K)보다 크면 두 s의 출력 라인이 결국 grep
청크로 분할될 수 있습니다.
답변2
글쎄, 임시 파일 없이 한 변수에서 stderr을 캡처하고 다른 변수에서 stdout을 캡처하는 것은 결코 쉬운 작업이 아닙니다.
이것은 유효한 예입니다
func() {
echo 'hello'
echo 'This is an error' >&2
}
result=$(
{ stdout=$(func) ; } 2>&1
echo -e "mysuperuniqueseparator\n"
echo -e "${stdout}\n"
)
var_out=${result#*mysuperuniqueseparator$'\n'}
var_err=${result%$'\n'mysuperuniqueseparator*}
나는 이것이 stderr을 stdout으로 리디렉션하고 두 변수를 구분 기호를 사용하여 변수에 넣은 다음 두 부분으로 나누는 더러운 방법이기 때문에 만족스럽지 않습니다.
추가하다:
분명히 이것은 명령의 표준 출력이나 표준 오류에 사용하는 구분 기호 문자열이 포함될 수 있으므로 신뢰할 수 없습니다.
답변3
임시 파일/fifo, 흥미로운 평가/파일 설명자 등이 없습니다.
x=$((echo 'this is stdout'; echo 'this is stderr' 1>&2; exit 123) 2> >(sed -r 's/^/2/g') 1> >(sed -r 's/^/1/g'))
echo $? ### exit code is preserved
# 123
echo "$x" | sed '/^2/d;s/^1//g' ### stdout
# this is stdout
echo "$x" | sed '/^1/d;s/^2//g' ### stderr
# this is stderr
참고: 대규모 출력에는 효율적이지 않을 수 있습니다.