Bash: Eval & Tee: 출력 수행 방법, 출력 캡처 및 오류 확인 방법

Bash: Eval & Tee: 출력 수행 방법, 출력 캡처 및 오류 확인 방법

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"

이러한 방법에서 teestdout은 원시 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

관련 정보