Ubuntu 16.04를 사용하여 #!/bin/bash
평가된 명령을 원합니다...
- 직접 출력 제공
- 출력을 변수로 가져오기
- 평가 결과 확인
# valid command
foo=$(eval "ls" | tee /dev/tty);
echo ${PIPESTATUS[@]}
echo $foo
# invalid command
foo=$(eval "ls -ßnonsense" | tee /dev/tty);
echo ${PIPESTATUS[@]}
echo $foo
PIPESTATUS
내 문제는 의미 있는 결과를 얻었을 때
- 완전히 제거했습니다
tee /dev/tty
(그렇지 않으면 첫 번째 파이프라인 명령의 일부로 모든 평가 실패를 마스킹합니다). - 아니면 괄호 밖에 넣으세요
foo=$(eval "ls" ) | tee /dev/tty;
- ...하지만 이 경우 더 이상 직접 출력이나 $foo 출력을 얻지 못합니다.
답변1
대신 사용하십시오 zsh
:
shell_code='ls' # or ls -ßnonsense...
{ foo=$(eval " $shell_code" >&1 >&3 3>&-); } 3>&1
print -r status=$? output=$foo
여기서는 원본 stdout(스크립트가 리디렉션 없이 터미널에서 실행되는 경우 제어 tty만)을 fd 3에 복사하고 eval
출력을 명령 대체 및 fd 3으로 리디렉션합니다( tee
출력을 위해 여러 번 리디렉션할 때 fd 메커니즘을 사용할 때 zsh 자체 ing 사용). .
지원되는 기타 쉘(Linux/Cygwin의 경우 ksh93은 아님)이 있는 시스템에서는 bash
다음과 같은 작업을 수행할 수 있습니다.pipefail
/dev/fd/<n>
shell_code='ls' # or ls -ßnonsense...
{
foo=$(
set -o pipefail
eval " $shell_code" 3>&- |
tee 4>&1 >&3 3>&- /dev/fd/4
)
} 3>&1
printf 'status=%s output=%s\n' "$?" "$foo"
open 일 때 pipefail
파이프의 종료 상태는 파이프에서 실패한 가장 오른쪽 명령의 종료 상태입니다. 실패하지 eval
않는 이상 여기에 있을 것입니다 tee
.
eval
무조건 종료 상태를 얻으려면 다음을 bash
사용할 수 있습니다.
shell_code='ls' # or ls -ßnonsense...
{
foo=$(
eval " $shell_code" 3>&- |
tee 4>&1 >&3 3>&- /dev/fd/4
exit "$PIPESTATUS"
)
} 3>&1
printf 'status=%s output=%s\n' "$?" "$foo"
이러한 방법에서 tee
stdout은 원시 stdout이며 명령 대체는 파이프를 통해 제공됩니다 /dev/fd/4
. 우리는 다른 방법( tee
명령 대체 파이프로 stdout 보내기, 일부 명령을 통해 원래 stdout에 쓰기 /dev/fd/<n>
) 대신 이 작업을 수행하고 있습니다. 비록 이렇게 하면 코드가 더 복잡해지기는 하지만 후자가 Linux에서 작동하지 않는다는 사실을 피합니다. 또는 Cygwin 시스템에서 여는 것은 /dev/fd/<n>
fd를 복사하는 것과 동일하지 않습니다 <n>
(그러나 명령 대체(소켓 쌍을 사용하는 ksh93이 아님)와 같이 파이프의 쓰기 끝을 가리키는 fd에 대해 이 작업을 수행하는 것은 기능적으로 동일합니다).
답변2
bash
이것은 , dash
, ksh93
, ksh88
, ash
(Bourne) 및 다음 으로 sh
테스트된 대부분의 (전부는 아니지만) Bourne 구문 쉘에서 작동하는 이식 가능한 솔루션입니다.zsh
for command in "ls -ßnonsense" "ls -ld /tmp"; do
foo=`{ eval "$command"; echo $? > /tmp/ps.$$; } | tee /dev/tty;`
st=`cat /tmp/ps.$$;rm /tmp/ps.$$`
echo "foo=$foo status=$st"
done