bash : 변수를 사용하여 stderr | stdout 리디렉션 저장


17

스크립트에 명령 옵션을 추가하는 것과 같은 변수를 통해 stdout 및 stderr을 리디렉션하는 방법이 있습니까?

예를 들어 스크립트가 있습니다.

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

OPT가 -p아무런 문제없이 대체 되고 bash가 옵션으로 해석한다는 것을 알 수 있습니다. 그러나 리디렉션은 디렉토리 이름으로 해석됩니다.

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory `123/123'
mkdir: created directory `123/123/123'
mkdir: created directory `>/dev'
mkdir: created directory `>/dev/null'
mkdir: created directory `2>&1'

bash를 말할 수있는 방법이 있습니까? $ VAR은 dirs 이름이 아닌 리디렉션입니다.

추신. 내가 잘못 가고있을 수도 있지만 스크립트에서 선택적 verbose 또는 non verbose 출력을 만들고 싶습니다. 그러나 비 상세 모드에서도 일부 출력이 필요하므로 스크립트 내 일부 명령에서만 전체 stdout 및 stderr을 리디렉션 할 수는 없습니다.

답변:


18

다른 해결책은 다음과 같습니다.

#!/bin/bash

verbose=0

exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
else
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null
fi

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

그런 다음 1>&3 2>&4출력을 보려는 명령에만 추가 하십시오.


큰. 이것이 바로 내가 본 것입니다. 감사합니다.
돌진

나는 이것이 어떻게 작동하는지 설명하는 기사 를 썼다
transang

5

"어떻게"는 다른 답변에서 잘 설명되었습니다. OP의 코드가 작동하지 않는 "이유"를 설명하고 싶습니다.

기조 연설은 변수 확장 전에 출력 리디렉션이 표시 된다는 것 입니다. 리디렉션은 실제로 변수 확장 후에 수행 되므로 (변수에 저장된 파일 이름으로 출력을 리디렉션 할 수있는 이유) 쉘 은 변수가 확장되기 전에 나중에 처리 할 리디렉션을 식별 합니다.

다시 말해, 일단 변수가 확장 되면 쉘이 경로 재 지정으로 처리 할 명령 문자열의 어느 부분을 이미 식별했기 때문에 경로 재 지정 문자 ( <또는 >등)를 고려 하기에는 "너무 늦습니다" .

자세한 내용은 아래에 나열된 1 단계와 3 단계를 참조하십시오.

LESS='+/^SIMPLE COMMAND EXPANSION' man bash

3

"디렉토리 이름"으로 해석하지 않습니다. > 인용되므로 문자 그대로 처리됩니다 (보다 구체적으로 문자열을 전송합니다 >dev/null 2>&1.이 문제를 해결하는 유일한 방법은 eval새 쉘을 사용 하거나 생성하는 것입니다.

귀하의 질문에 언급 된 "자세한"문제에 대해서는 다음과 같이하십시오.

verbose=1
if (( verbose )); then
    mkdir -v -p /foo
else
    mkdir -p /foo > /dev/null 2>&1
fi

1

변수에 공백이 많으며 제대로 평가되지 않습니다. eval이를 설정하는 데 사용할 수 있습니다.

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

이를 통해 $ OPT를 하나의 ( ) 대신 두 개의 인수 ( -p-v) 로 나누고 -p -v$ TEST와 동일하게 할 수 있습니다. 현재 디렉토리에 디렉토리 /dev/null가있을 가능성이 거의 없으므로 사용하도록 변경되었습니다 dev.


0

enzotib의 대답은 좋은 파일 설명자 마술을 사용하지만 더 간단한 해결책은 eval라인을 사용 하는 것입니다 ( 그러나 프로세스 오버 헤드 추가됩니다).

$ rm /tmp/foo
$ ll /tmp/foo
ls: cannot access /tmp/foo: No such file or directory
$ FOO=">/tmp/foo"
$ date $FOO
date: invalid date '>/tmp/foo'
$ cat /tmp/foo
cat: /tmp/foo: No such file or directory
$ eval date $FOO
$ cat /tmp/foo
Thu Dec 13 14:08:17 EST 2018
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.