"부작용"을 이해하거나 하나의 명령에 여러 명령이 포함되어 있습니까?

"부작용"을 이해하거나 하나의 명령에 여러 명령이 포함되어 있습니까?

이 질문은 POSIX 호환 쉘 스크립트에 중점을 둡니다.

변수는 일반적으로 다음을 통해 증가됩니다.

i=3
: $(( i += 1 ))
echo "return code = $?"        # return code = 0
echo "i = $i"                  # i = 4

이 명령을 $(( i += 1 ))"부작용"이라고 합니까 :?

:( equals에 대한 내용을 읽었습니다 . or 로 바꾸려고 true시도했는데 작동했습니다. or로 바꾸면 예상대로 반환 코드가 1이 됩니다.):truefalsefalse

값이 성공적으로 증가했지만 $i할당이 작동하지 않아 "부작용"이 발생하는 이유는 무엇입니까?

a='four'
: a='five'
echo "return code = $?"        # return code = 0
echo "a = $a"                  # a = four

때로는 하나의 명령으로 여러 명령을 실행하는 스크립트를 볼 수 있습니다. 대부분의 경우 사람들은 이 구조를 사용 하여 IFS. IFS='' read -r REPLY이것은 "부작용"이라는 동일한 구조입니까? 그러나 모든 부작용은 a=6현재 셸 내에서 실제 영향을 미칩니다. 숙제는 여기서 이루어집니다.

a=6 b=7 c=8
echo "a = $a"                  # a = 6
echo "b = $b"                  # b = 7
echo "c = $c"                  # c = 8

이 구조를 "부작용"이라고 하나요? 그에 대한 기록은 어디서 찾을 수 있나요? 아니면 어디서 배울 수 있나요? 아래 POSIX 문서에서는 이 구조를 찾을 수 없습니다.

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09

답변1

이를 :빈 명령이라고 합니다. 해당 문서는 다음에서 찾을 수 있습니다 man bash.

:[논쟁]

효과가 없습니다. 명령은 매개변수를 확장하고 지정된 리디렉션을 수행하는 것 외에는 아무 작업도 수행하지 않습니다. 반환 상태는 0입니다.

또는 bash 쉘을 실행하는 경우 다음을 사용하십시오 help :.

$ help :
:: :
    Null command.
    
    No effect; the command does nothing.
    
    Exit Status:
    Always succeeds.

POSIX 사양에 있습니다.여기:

이름

콜론 - null 유틸리티 요약: [매개변수...]

설명하다

이 유틸리티는 명령 매개변수만 확장할 수 있습니다. if 명령의 then 조건과 같이 명령이 필요할 때 사용되지만 명령은 아무 작업도 수행하지 않습니다.

이제 당신이 말하는 부작용은 위의 첫 번째 문장에 설명된 결과입니다. "명령은 아무 작업도 수행하지 않습니다.주장을 확장하는 것 외에도". :는 명령이므로 뒤에 오는 모든 내용은 매개변수입니다. $(( ))이를 "산술 확장"이라고 하며 man bash다음과 같이 문서화되어 있습니다.

산술 확장

산술 확장을 사용하면 산술 표현식을 평가하고 결과를 바꿀 수 있습니다.

산술 확장의 형식은 다음과 같습니다.

$((expression))

표현식은 큰따옴표로 묶인 것처럼 처리되지만, 괄호 안의 큰따옴표는 특별히 처리되지 않습니다. 표현식의 모든 토큰은 매개변수 및 변수 확장, 명령 대체 및 따옴표 제거를 거칩니다. 결과는 평가할 산술 표현식으로 처리됩니다. 산술 확장은 중첩될 수 있습니다.

[. . .]

so는 $(( i += 1 ))" i하나를 추가하고 결과를 반환"을 의미합니다. 그러나 이에 대해서는 평가가 필요하며,확장하다, 이것이 와 함께 사용되는 것을 볼 수 있는 이유입니다 :. :매개변수가 확장되므로 평균값 : $(( i += 1 ))i1씩 증가합니다. 단독으로 실행 하려고 하면 $(( i += 1 ))먼저 (귀하의 예에서)로 확장된 4다음 쉘이 4명령으로 실행을 시도하고 오류를 반환합니다.

$ $(( i += 1 ))
bash: 4: command not found

그러나 실행하면 : $(( i += 1 ))쉘은 두 가지 작업을 수행합니다. 첫째, 산술 확장을 적용하고 다음 값을 i사용 4합니다 .: 4:

$ : 4
$ 

그런데 왜 더 간단하고 POSIX 대신에 이 작업을 수행하려는지 모르겠습니다.

$ i=3
$ i=$(( i + 1 ))
$ echo "$i"
4

또는 POSIX 쉘에서는 가능 bash하지만 POSIX 쉘에서는 그렇지 않습니다.

$ i=3
$ (( i += 1 ))
$ echo "$i"
4

여기서 다음 요점은 이것이 variable=value command다른 짐승이고 다르게 취급된다는 것입니다. POSIX 사양의 관련 부분은 다음과 같습니다.2.9.1 간단한 명령, 가장 관련성이 높은 부분은 다음과 같습니다.

"간단한 명령"은 임의의 순서로 선택적인 변수 할당 및 리디렉션의 시퀀스이며 선택적으로 단어와 리디렉션이 뒤따르고 제어 연산자에 의해 종료됩니다.

주어진 간단한 명령을 실행해야 할 때 [. .]에서는 명령 텍스트의 처음부터 끝까지 다음 확장, 할당 및 리디렉션을 수행해야 합니다.

  1. 쉘 구문 규칙에 따라 변수 할당 또는 리디렉션으로 식별된 단어는 3단계와 4단계의 처리를 위해 저장됩니다.

  2. 변수 할당이나 리디렉션이 아닌 단어는 확장되어야 합니다. 확장 후 남은 필드가 있는 경우 첫 번째 필드는 명령 이름으로 처리되어야 하며 나머지 필드는 명령에 대한 인수입니다.

  3. 리디렉션은 리디렉션에 설명된 대로 수행되어야 합니다.

  4. 물결표 확장, 매개변수 확장, 명령 대체, 산술 확장 및 따옴표 제거를 할당하기 전에 모든 변수 할당을 확장해야 합니다.

그리고:

변수 할당은 다음과 같이 수행되어야 합니다.

[. . .]

  • 명령 이름이 특수 내장 유틸리티나 함수가 아닌 경우 명령의 실행 환경 내보내기 변수를 [...]로 지정해야 합니다.

[. . .]

  • 명령 이름이 특수 내장 유틸리티인 경우 변수 할당은 현재 실행 환경에 영향을 미칩니다. set -a 옵션이 켜져 있지 않으면 지정되지 않습니다(세트 참조).

  • 특수 내장 유틸리티를 실행하는 동안 변수가 내보낸 속성을 가져올지 여부

  • 특수 내장 유틸리티가 완료된 후에도 변수 할당의 결과로 얻은 내보내기 속성이 여전히 존재합니까?

따라서 쉘이 이를 실행하기 위해 명령을 읽을 때 먼저 이를 분석하여 변수 할당( foo=bar)처럼 보이는 것을 찾은 다음 관련 값을 할당합니다. 이 할당은 "정상" 명령인 경우에만 해당 명령에 영향을 미칩니다. 명령이 실행되는 환경이 작동하는 이유입니다.

$ foo=bar sh -c 'echo "foo is $foo"'
foo is bar
$ echo "foo is $foo"
foo is 

변수 할당은 sh -c명령의 실행 환경에서 작동하고 존재하지만 명령을 시작한 상위 셸에는 존재하지 않습니다. 이는 쉘 명령 처리의 일부일 뿐이며 쉘에 영향을 주지 않고 단일 명령에 대해서만 변수를 설정하는 방법입니다.

명령이 특수 내장 명령인 경우(예를 들어) 할당이 명령 뒤에 남아 있는지 여부는 지정되지 않습니다 :. 이는 완료 후에 변수를 사용할 수 있게 var=foo :만드는 일부 쉘이 있음을 의미 하지만 이는 POSIX에서 필수가 아니며 다른 쉘은 다른 방식으로 작동합니다.$varcommand

$ cat foo.sh 
foo=bar :
echo "foo is $foo"
$ awk -F'/' '/^\//{print $NF}' /etc/shells | sort -u | 
  while read shell; do 
    echo "==== $shell ===="; 
    "$shell" foo.sh; 
done
==== bash ====
foo is 
==== dash ====
foo is bar
==== fish ====
foo is 
==== ksh ====
foo is bar
==== mksh ====
foo is bar
==== rbash ====
foo is 
==== sh ====
foo is bar
==== yash ====
foo is bar
==== zsh ====
foo is 

어쨌든, 이 모든 것이 바로 while IFS= read ...여러분이 다음과 같이 보고 구성하는 이유입니다. 변수를 엉망으로 만들고 싶지 않으므로 $IFS다른 값을 갖는 데 필요한 특정 명령을 실행하기 위해 변수를 변경하면 됩니다.

마지막으로 이 방법이 효과적인 이유에 대해 이야기해 보겠습니다.

a=6 b=7 c=8

거기에는 명령이 없고 단지 변수 할당만 있기 때문입니다. 따라서 이러한 변수는 실제로 현재 셸에 할당됩니다.

답변2

이 명령을 $(( i += 1 ))"부작용"이라고 합니까 :?

아니요. 부가가치 i는 부작용이다.표현식 평가(명령이 아님) $(( i += 1 )).

즉, i3이면 표현식은 $(( i += 1 ))값으로 확장되지만 44를 다시 저장하는 부작용도 있습니다 i.

귀하의 경우에는 표현식을 평가하고 있습니다.오직부작용 때문에 확장되는 가치에 관심이 없습니다. 하지만 아직은하다가 뭔가로 확장되고,
$(( i += 1 ))그렇게 하면 4: command not found. 이 시점에서 우리는 :아무것도 하지 않고 인수를 무시하는 명령을 살펴보겠습니다 . : $(( i += 1))로 확장하면 : 4어떤 작업이든 성공적으로 수행하는 명령입니다. 하지만부작용으로해당 매개변수가 확장되어 i이제 4가 포함됩니다.

관련 정보