독자의 이익을 위해 여기 에이 레시피
- stderr를 변수로 잡기 위해 oneliner로 재사용 가능
- 여전히 명령의 리턴 코드에 대한 액세스를 제공합니다
- 임시 파일 디스크립터 3을 희생합니다 (물론 변경 가능)
- 그리고이 임시 파일 설명자를 내부 명령에 노출시키지 않습니다
당신이 안으로 stderr
일부 를 잡고 싶다면 할 수 있습니다command
var
{ var="$( { command; } 2>&1 1>&3 3>&- )"; } 3>&1;
그 후에는 모든 것이 있습니다.
echo "command gives $? and stderr '$var'";
command
간단한 경우 (와 같지 않음 a | b
) 내부를 {}
멀리 둘 수 있습니다.
{ var="$(command 2>&1 1>&3 3>&-)"; } 3>&1;
재사용이 용이 한 기능으로 싸여 있음 bash
(아마도 버전 3 이상 필요 local -n
) :
: catch-stderr var cmd [args..]
catch-stderr() { local -n v="$1"; shift && { v="$("$@" 2>&1 1>&3 3>&-)"; } 3>&1; }
설명 :
local -n
별명 "$ 1"(에 대한 변수 catch-stderr
)
3>&1
파일 설명자 3을 사용하여 stdout 포인트를 저장합니다.
{ command; }
(또는 "$ @")는 출력 캡처 내에서 명령을 실행합니다 $(..)
- 정확한 순서는 여기서 중요합니다 (잘못된 방법으로 파일 디스크립터를 잘못 섞습니다).
2>&1
stderr
출력 캡처로 리디렉션$(..)
1>&3
stdout
출력 캡처에서 $(..)
다시 stdout
파일 디스크립터 3에 저장된 "외부"로 경로 재 지정합니다. 이는 stderr
여전히 FD 1이 이전에 지정한 위치를 나타냅니다.$(..)
3>&-
그런 다음 더 이상 필요 command
하지 않은 파일 디스크립터 3을 닫아 갑자기 알 수없는 열린 파일 디스크립터가 나타나지 않게합니다. 외부 셸에는 여전히 FD 3이 열려 있지만 command
보이지 않습니다.
- 후자는 중요합니다. 일부 프로그램
lvm
은 예기치 않은 파일 디스크립터에 대해 불평 하기 때문 입니다. 그리고 우리가 무엇을 포착 할 것인지에 lvm
대해 불평합니다 stderr
!
적절하게 조정하면이 레시피로 다른 파일 설명자를 잡을 수 있습니다. 물론 파일 디스크립터 1을 제외하고 (여기서 리디렉션 로직은 잘못되었지만 파일 디스크립터 1의 경우 var=$(command)
평소처럼 사용할 수 있습니다 ).
파일 디스크립터 3이 희생된다는 점에 유의하십시오. 해당 파일 디스크립터가 필요한 경우, 번호를 자유롭게 변경하십시오. 그러나 일부 쉘 (1980 년대 이후)은 99>&1
인수가 9
뒤에 오는 것으로 이해할 수 있습니다 9>&1
(이것은 문제가되지 않습니다 bash
).
또한 변수를 통해이 FD 3을 구성 할 수있는 것은 쉬운 일이 아닙니다. 이렇게하면 내용을 읽을 수 없게됩니다.
: catch-var-from-fd-by-fd variable fd-to-catch fd-to-sacrifice command [args..]
catch-var-from-fd-by-fd()
{
local -n v="$1";
local fd1="$2" fd2="$3";
shift 3 || return;
eval exec "$fd2>&1";
v="$(eval '"$@"' "$fd1>&1" "1>&$fd2" "$fd2>&-")";
eval exec "$fd2>&-";
}
보안 정보 : 처음 3 개의 인수를 catch-var-from-fd-by-fd
타사에서 가져 와서는 안됩니다. 항상 "정적"방식으로 명시 적으로 제공하십시오.
그러니 catch-var-from-fd-by-fd $var $fda $fdb $command
절대 안돼!
변수 변수 이름을 전달하는 경우 최소한 다음과 같이 수행하십시오.
local -n var="$var"; catch-var-from-fd-by-fd var 3 5 $command
이것은 여전히 모든 악용으로부터 당신을 보호하지는 않지만 최소한 일반적인 스크립팅 오류를 감지하고 피하는 데 도움이됩니다.
노트:
catch-var-from-fd-by-fd var 2 3 cmd..
와 같다 catch-stderr var cmd..
shift || return
올바른 인수 수를 잊어 버린 경우 추악한 오류를 방지하는 방법입니다. 아마도 쉘을 종료하는 것이 다른 방법 일 것입니다 (그러나 이것은 명령 줄에서 테스트하기가 어렵습니다).
- 루틴은 이해하기 쉽도록 작성되었습니다. 함수가 필요하지 않도록 함수를 다시 작성할 수는
exec
있지만 실제로는 추악합니다.
- 이 루틴은
bash
불필요 하게 다시 작성할 수 있으므로 필요하지 않습니다 local -n
. 그러나 지역 변수를 사용할 수 없으며 매우 추악합니다!
- 또한
eval
s는 안전한 방식으로 사용됩니다. 일반적으로 eval
위험한 것으로 간주됩니다. 그러나이 경우 "$@"
(임의의 명령을 실행하기 위해)를 사용하는 것보다 더 나쁘지 않습니다 . 그러나 여기에 표시된대로 정확하고 올바른 인용 부호를 사용해야합니다 (그렇지 않으면 매우 위험합니다 ).
ERROR=$(./useless.sh | sed 's/Output/Useless/' 2>&1 1>/dev/ttyX)