Bash에서 리디렉션 사용에 대한 많은 질문이 SE에서 제기되고 답변되었음을 발견했습니다.구현하다, 하지만 아무도 내 질문에 대답하지 않는 것 같습니다.
내가 달성하고 싶은 것은 모든 출력을 다음으로 리디렉션하는 것입니다.표준 에러스크립트에서 임시 파일에 저장하고 다음으로 복원합니다.표준 에러스크립트가 성공적으로 종료되지 않는 경우에만 해당됩니다. 콘텐츠 복원 기능표준 에러종료에 실패한 경우 호출자에게 오류에 대한 정보를 반환하는 데 필요합니다. 리디렉션표준 에러/dev/null
관련 없는 노이즈와 유용한 정보 는 삭제 됩니다 . 명시적인 임시 파일은 다른 많은 문제를 추가하므로 가능하면 피해야 합니다.https://dev.to/philgibbs/avoiding-temporary-files-in-shell-scripts). 콘텐츠표준 출력호출자에게 투명하게 반환되어야 합니다. 스크립트가 성공적으로 종료되지 않으면 호출자는 이를 무시하지만 스크립트는 이에 대해 신경 쓸 필요가 없습니다.
그 이유는 모든 출력을 고려하는 다른 프로그램에서 스크립트가 호출되기 때문입니다.표준 에러0이 아닌 종료 코드를 테스트하는 대신 오류가 발생합니다. 다음 예에서는OpenSSL에코 진행 표시기표준 에러이는 오류를 나타내지 않으며 명령이 성공적으로 완료된 후에 무시할 수 있습니다.
아래는 내 스크립트의 단순화된 버전입니다.OpenSSL이는 임의적이고 더 복잡한 지침에 대한 자리 표시자일 뿐입니다.)
#!/bin/bash
set -euo pipefail
# Redirect stderr to temp fd 3
exec 3>&2
# In case of error, copy contents of fd 3 to stderr
trap 'cat <&3 >&2' ERR
# Upon exit, restore original stderr and close fd 3
trap 'exec 2>&3 3>&-' EXIT
# This nonetheless outputs the progress indicator to stderr
openssl genpkey -algorithm RSA
하지만 스크립트가 계속 인쇄되기 때문에 분명히 뭔가가 빠졌습니다.표준 에러성공적으로 종료되었지만 이제 실패 시 차단됩니다. 리디렉션하는 방법이 헷갈리는 것 같아요.구현하다일하다. 내가 뭘 잘못했나요?
답변1
chronic
moreutils는 필요한 거의 모든 작업을 수행합니다.
chronic cmd
cmd의 stdout 및 stderr은 실패하거나 종료되지 않는 한 폐기됩니다 cmd
. 이 경우 chronic
stdout 출력은 stdout에 기록되고 stderr 출력은 메모리에 보관된 stderr에 기록됩니다.
chronic
perl
임의의 데이터를 처리하고 두 스트림에서 독립적으로 읽도록 작성되었습니다 . 반면에 zsh 이외의 쉘은 차단 또는 NUL 문자 때문에 변수에 임의의 출력을 저장할 수 없습니다. 또한 명령 대체( 에서도 zsh
)는 후행 줄 바꿈을 제거합니다.
여기에서 처음부터 삭제하더라도 임시 파일을 계속 사용할 수 있으며 이와 관련된 대부분의 문제를 제거할 수 있습니다(예: 대부분의 쉘이 여기 문서에서 수행하는 작업).
#! /bin/bash -
set -o nounset -o errexit -o pipefail
tmp=$(mktemp)
exec 3>&2 2> "$tmp" 4< "$tmp"
rm -f -- "$tmp"
trap '[ "$?" -eq 0 ] || cat <&4 >&3' EXIT
cmd1
cmd2
답변2
저를 올바른 방향으로 안내하는 데 도움을 주신 위의 댓글에 있는 모든 분들께 감사드립니다. 이게 내가 찾던 답인 것 같아, 정말 영감을 받았어또 다른 SE 답변은 다음과 같습니다.:
#!/bin/bash
set -euo pipefail
shopt -s inherit_errexit
trap 'printf "%s\n" "$_ERR" >&2' ERR
{ _ERR=$({
# Arbitrary commands go here
openssl genpkey -algorithm RSA
} 2>&1 >&3 3>&-); } 3>&1
추가적인 개선을 위한 아이디어를 환영합니다.
제안해 주신 @StéphaneChazelas에게 감사드립니다.