!["부작용"을 이해하거나 하나의 명령에 여러 명령이 포함되어 있습니까?](https://linux55.com/image/220712/%22%EB%B6%80%EC%9E%91%EC%9A%A9%22%EC%9D%84%20%EC%9D%B4%ED%95%B4%ED%95%98%EA%B1%B0%EB%82%98%20%ED%95%98%EB%82%98%EC%9D%98%20%EB%AA%85%EB%A0%B9%EC%97%90%20%EC%97%AC%EB%9F%AC%20%EB%AA%85%EB%A0%B9%EC%9D%B4%20%ED%8F%AC%ED%95%A8%EB%90%98%EC%96%B4%20%EC%9E%88%EC%8A%B5%EB%8B%88%EA%B9%8C%3F.png)
이 질문은 POSIX 호환 쉘 스크립트에 중점을 둡니다.
변수는 일반적으로 다음을 통해 증가됩니다.
i=3
: $(( i += 1 ))
echo "return code = $?" # return code = 0
echo "i = $i" # i = 4
이 명령을 $(( i += 1 ))
"부작용"이라고 합니까 :
?
:
( equals에 대한 내용을 읽었습니다 . or 로 바꾸려고 true
시도했는데 작동했습니다. or로 바꾸면 예상대로 반환 코드가 1이 됩니다.):
true
false
false
값이 성공적으로 증가했지만 $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 ))
이 i
1씩 증가합니다. 단독으로 실행 하려고 하면 $(( 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 간단한 명령, 가장 관련성이 높은 부분은 다음과 같습니다.
"간단한 명령"은 임의의 순서로 선택적인 변수 할당 및 리디렉션의 시퀀스이며 선택적으로 단어와 리디렉션이 뒤따르고 제어 연산자에 의해 종료됩니다.
주어진 간단한 명령을 실행해야 할 때 [. .]에서는 명령 텍스트의 처음부터 끝까지 다음 확장, 할당 및 리디렉션을 수행해야 합니다.
쉘 구문 규칙에 따라 변수 할당 또는 리디렉션으로 식별된 단어는 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에서 필수가 아니며 다른 쉘은 다른 방식으로 작동합니다.$var
command
$ 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 ))
.
즉, i
3이면 표현식은 $(( i += 1 ))
값으로 확장되지만 4
4를 다시 저장하는 부작용도 있습니다 i
.
귀하의 경우에는 표현식을 평가하고 있습니다.오직부작용 때문에 확장되는 가치에 관심이 없습니다. 하지만 아직은하다가 뭔가로 확장되고,
$(( i += 1 ))
그렇게 하면 4: command not found
. 이 시점에서 우리는 :
아무것도 하지 않고 인수를 무시하는 명령을 살펴보겠습니다 . : $(( i += 1))
로 확장하면 : 4
어떤 작업이든 성공적으로 수행하는 명령입니다. 하지만부작용으로해당 매개변수가 확장되어 i
이제 4가 포함됩니다.