bash 스크립트에서 PIPESTATUS 및 출력을 모두 얻는 방법


9

이 명령으로 파일의 마지막 수정 날짜를 얻으려고합니다.

TM_LOCAL=`ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'`

이 줄을 실행 한 후 TM_LOCAL의 값은 "2012-05-16 23:18"과 같습니다.

또한 PIPESTATUS를 확인하여 오류가 있는지 확인하고 싶습니다. 예를 들어, 파일이 존재하지 않으면 ls2를 리턴하지만 리턴 $?값이 0이므로 값이 0입니다 awk.

이 명령을 단독으로 실행하면 ls의 반환 값을 확인할 수 있습니다. ${PIPESTATUS[0]}

ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'

그러나 $PIPESTATUS첫 번째 예제 에서처럼 출력을 변수에 할당하면 예상대로 작동하지 않습니다. 이 경우 $PIPESTATUS배열에는 다음과 같은 요소가 1 개만 있습니다.$?

그래서 문제는 어떻게 둘 다 얻고 동시에 $PIPESTATUS출력을 변수에 할당 할 수 있습니까?

답변:


8

당신은 이것을 할 수 있습니다 :

TM_LOCAL=$(ls -l --time-style=long-iso ~/.vimrc | \
             awk '{ print $6" "$7 }' ; exit ${PIPESTATUS[0]} )

그런 다음 $?의 리턴 코드가됩니다 ls. 둘 이상의 파이프 파트에서 리턴 코드가 필요한 경우 작동하지 않습니다 (그러나 출력이 너무 크지 않은 경우 파이프 라인을 분할 할 수 있음).

전체 PIPESTATUS배열과 출력 을 얻는 데 다소 비싼 방법이 있습니다. 매우 우아하지는 않지만 다른 것을 찾지 못했습니다.

result=$(echo -e "a\nb\nc" | \
          ( cat ; exit 1 ) | \
          ( cat ; exit 42 ) ; echo ${PIPESTATUS[@]})
output=$(head -n -1 <<< "$result")
status=($(tail -n 1 <<< "$result"))
echo "Output:"
echo "$output"
echo "Results:"
echo "${status[@]}"

다음을 제공합니다.

Output:
a
b
c
Results:
0 1 42

이것은 내 경우에는 효과가 있지만 완전한 pipestatus 배열과 출력을 얻는 방법이 있는지 여전히 궁금합니다.
Mustafa Serdar Şanlı

3

파이프 된 명령 순서에서로 0이 아닌 가장 오른쪽에있는 종료 코드를 가져 오려면 set -o pipefailin bash을 사용하십시오 $?. 보낸 사람 man bash:

설정된 경우 파이프 라인의 리턴 값은 0이 아닌 상태로 종료하는 마지막 (가장 오른쪽) 명령의 값이거나 파이프 라인의 모든 명령이 성공적으로 종료되면 0입니다. 이 옵션은 기본적으로 비활성화되어 있습니다.

그런 다음 간단히 액세스 할 수 있습니다 $?. 사용이 set +o pipefail다시 비활성화합니다.


2

여기서 문제는 명령을 실행하자마자 PIPESTATUS가 완전히 사라진다는 것입니다. bash 버전 2 이상에서 다음과 같은 방법으로 완전한 PIPESTATUS 배열을 얻을 수 있습니다.

declare -a status
status=(${PIPESTATUS[@]})

액세스 그런 다음 ${status[0]}, ${status[1]}


2

"당신이 기대하는 것"의 주된 문제점은 역 따옴표 안에있는 명령이 서브 쉘에서 실행된다는 것입니다. $PIPESTATUS거기에 존재하고 상태가 반환되면 단일 실행 파일 (또는 셸 스크립트)을 실행 한 것과 동일한 규칙을 따릅니다. backquote 명령의 상태는 가장 오른쪽 ( awk) 상태입니다.

@ Daniel Beck이 말한 것을 구현하려면 pipefail서브 쉘 에서 옵션을 설정하십시오 .

TM_LOCAL=`set -o pipefail; ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'` 이제 $?이후에 저장된 상태는 ls(0이 아닌 경우) 의 상태가 됩니다.

그러나 명시 적 if [ -f ~/.vimrc ];... 테스트가 더 읽기 쉽다고 생각합니다 .

PIPESTATUS전자에 대한 임시 파일이나 후자를 문자열로 마샬링하지 않고 변수로 출력을 반환 할 수 없습니다 .


0

종료 상태가 0이 아닌 경우에만 이메일 fron cron을 보내려고했습니다.

트릭은 파이프 라인 끝의 stdin을 서브 쉘에 넣어야하지만 PIPESTATUS 값을 숨기는 것 같습니다 ...

테스트 크론은 일부 출력을 뱉어 내고 1 또는 0으로 종료합니다.

./testcron | (test ${PIPESTATUS[0]} -ne 0 || mail -s "testcron output" paul)

업데이트 : 파이프 라인 명령이 처리 될 때까지 PIPESTATUS가 표시되지 않습니다


0

한 가지 옵션은을 호출하여 수정 시간을 얻기 전에 파일이 있는지 확인하는 것 stat입니다. stat타임 스탬프에서 원하는 것보다 약간 더 많이 반환 하므로 매개 변수 확장을 사용하여 잘라낼 수 있습니다.

GNU stat(예 : Linux)를 사용하면 다음을 실행할 수 있습니다.

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -c '%y' ~/.vimrc 2>/dev/null)
TM_LOCAL=${TM_LOCAL%:*}  # Safe to do, even if stat fails

Mac OS X 및 기타 BSD 시스템에서 stat구문은 다르며 시간 형식을 지정할 수 있습니다.

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' ~/.vimrc 2>/dev/null)

이제 GNU 답변은 무엇입니까?로 변경하면 $TM_LOCAL안전하다고 말합니다 . 이전 값이 없을 것으로 예상되는 경우에만 안전합니다. 이전에 값이 2020-02-27 17:14있고 ~/.vimrc파일 이 없다고 가정 하십시오. 그런 거라고 2020-02-27 17. 따라서 그 두 줄을 추가 &&또는 (바람직하게 읽을 수 없기 때문에) if스탠자를 사용하여 연결 합니다.
Adam Katz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.