셸 변수를 설정한 후 하위 프로세스 호출이 실패함

셸 변수를 설정한 후 하위 프로세스 호출이 실패함

OPTERR나는 동작에 영향을 미치는 쉘 변수가 있는 getopts를 사용하고 있습니다 . OPTERRgetopts의 동작에 영향을 주기 위해 getopts의 값을 변경하고 같은 줄에서 getopts를 호출하고 싶지만 OPTERR기본값으로 되돌리고 싶습니다. 따라서 변수 변경 명령 ​​호출을 혼합하는 과정에 대해 약간 모호하다는 점을 고려하여 간단한 것을 시도해 볼까 생각했습니다 echo. 이는 일련의 셸 명령과 그 출력으로, 그 중 일부는 나에게 이해가 되지 않습니다.

$ echo OPTERR
1
$ OPTERR=0 echo $OPTERR
1

지금은 여기서 멈추겠습니다. 두 번째 명령의 출력이 "0"이어야 하지 않나요? 그래서 이 질문을 하기 전에 나는 머리를 쥐어짜며 다음 명령이 서브셸에 있어야 하기 때문에 그럴 것이라고 생각했습니다. 그래서 시도해봤는데...

$ OPTERR=0 (echo $OPTERR)
-bash: syntax error near unexpected token `('

이것은 더욱 놀라운 일이다. 위 구성에 구문 오류가 있는 경우 서브쉘을 실행하기 위해 쉘 변수의 값을 어떻게 변경할 수 있습니까? (또한 echo 명령 뒤에 터미널 ";"을 넣으려고 시도했지만 동일한 결과를 얻었습니다.) 나도 시도해 봤는데...

$OPTERR=0 bash -c 'echo $OPTERR'
1

그러므로 거기에도 기쁨이 없습니다. 다른 방법을 택했는데..

$function sf() { echo $OPTERR }
$sf
1
$OPTERR=0 sf
0
$sf
1

성공! ! 그런데 왜? 이 기능은 특히 서브쉘이 아니며(그렇다고 생각하지 않습니다), 이는 실제로 제가 원하는 것이 아닙니다(비록 내 응용 프로그램에서 작동하도록 만들 수는 있지만). 작동하는 또 다른 공식은 다음과 같습니다.

$function sf() { (OPTERR=0; echo $OPTERR;) }
$sf
0
$echo $OPTERR
1

이것은 내가 원하는 것과 매우 유사하지만 물론 실제 스크립트(내가 사소하지는 않음 ) 는 echo이를 수행하도록 의도되었으며 나머지 스크립트에서 볼 수 있는 변수를 변경해야 합니다. 그래서 간단한 스크립트를 다음과 같은 간단한 변수 세트로 변경했습니다.getoptsgetoptsecho

$function sf() { foo='bar'; (foo='check'; echo $foo;); echo $foo; }
$sf
check
bar

오! ! 그래서 getopts내가 원하는 환경으로 호출을 할 수는 있는데, 서브쉘에서는 어떤 값도 얻을 수 없습니다. 나는 여기에 나열하기에는 너무 당황스러운 foo 및 모든 종류의 항목을 내보내려고 시도했지만 여기에 내 문제가 있습니다. 내 모든 실험을 종합하면 이 모든 것이 어떻게 작동해야 하는지에 대한 근본적으로 잘못된 모델이 드러날 것입니다. 내 이해에 무엇이 빠졌습니까? 올바른 접근 방식은 무엇입니까?

다시 한번 말씀드리지만, 제가 하고 싶은 것은 with 를 사용하여 0으로 설정되는 함수를 만드는 것입니다 getopts. OPTERR이상적으로는 함수가 호출되는 줄에 설정하지 않고 OPTERR함수 외부에서 복원되도록 설정하는 것입니다. 대부분의 OPTERR중요한 것은 실제로 처리할 수 있는 방식으로 getopts문제가 많은 것처럼 들리지만 꽤 합리적이며 OPTERR이 변수의 존재는 그것이 가능해야 함을 시사합니다.

답변1

$ echo $VAR

$VAR이는 쉘이 명령줄에서 확장한 후에만 변수 할당을 적용하기 때문에 이전 값을 제공합니다 .

IFS= read -r foo그러나 웹사이트에서 자주 볼 수 있는 구성은 명령줄에서 가져오는 read대신 내부적으로 사용하기 때문에 작동합니다. IFS마찬가지로 OPTERR=0 getopts ...작동해야 합니다.

$ cat arg.sh
#!/bin/bash
OPTERR=0 getopts a:b var
echo "var: $var OPTERR: $OPTERR"

$ bash arg.sh -z
var: ? OPTERR: 1

옵션이 유효하지 않은 경우에도 -z오류 메시지가 나타나지 않습니다.


$ OPTERR=0 bash -c 'echo $OPTERR'

특별하기 때문에 좀 특별해요 OPTERR. Bash 매뉴얼 페이지는 다음과 같이 말합니다.

OPTERR값으로 설정하면 1Bash는 내장 명령에 의해 생성된 오류 메시지를 표시합니다 getopts. OPTERR쉘이 호출되거나 쉘 스크립트가 실행될 때마다 1로 초기화됩니다.

하지만 아이디어는 정확하며 일반 변수와 함께 작동합니다.

$ FOO=123 bash -c 'echo $FOO'
123

내가 하고 싶은 것은 다음을 사용하는 함수를 만드는 것입니다.getopts

함수의 인수를 구문 분석하고 이를 기본 프로그램(예: dothis -a; dothis -b -c)에서 여러 번 호출하고 해당 함수를 사용하여 셸의 인수( )를 구문 분석하지 않는 경우 변수도 수정해야 한다는 점 parse_args "$@"을 기억해야 합니다 . 또한 해당 기능에 맞게 현지화해야 합니다.getoptsOPTIND

예를 들어, 여기에서 두 번째 함수 호출에는 옵션이 표시되지 않습니다.

foo() { while getopts "abcd" opt; do echo "$opt"; done; };
foo -a -a
foo -b -b

이전 기능과 결합하면 이 기능은 자동으로 작동합니다.

foo() {
    local OPTIND=1
    while OPTERR=0 getopts "abcd" opt; do
        echo "$opt"
    done
}

답변2

함수 호출 중에 OPTERR을 0으로 설정해야 하는 경우 Gordon Davisson이 제안한 대로 이를 로컬 변수로 설정하세요.

#!/bin/bash

myfunc() {
  local OPTERR=0
  printf "Inside myfunc, OPTERR=%d\n" "$OPTERR"
  while getopts ":a:" opt; do
    echo $opt is $OPTARG
  done
}

printf "Before calling myfunc, OPTERR=%d\n" "$OPTERR"
myfunc
printf "After calling myfunc, OPTERR=%d\n" "$OPTERR"

결과 :

Before calling myfunc, OPTERR=1
Inside myfunc, OPTERR=0
After calling myfunc, OPTERR=1

관련 정보