특정 명령줄 플래그를 $debug
다음으로 설정 true
하거나 다음을 기반으로 할 수 있는 간단한 디버깅 스타일을 고려해보세요 .false
$debug && echo "Something strange just happened" >&2
${debug:-false}
모든 기능을 갖춘 -type 함수와 같이 값 설정을 방지하는 더 좋은 방법이 있다는 것을 알고 있지만 logMessage()
지금은 이를 제쳐두겠습니다.
$debug
여전히 설정되지 않았거나 비어 있는 나쁜 경우를 가정합니다. 나는 $debug && echo …
그러한 null 값이 $debug
구문 분석되고 로 평가되어 && echo …
후속 구문 오류가 발생할 것으로 예상했습니다. 그런데 오히려 그런 평가를 받고 : && echo …
최종적으로는 실행되는 것 같다 echo
.
bash
으로 ksh
테스트 했는데 dash
시나리오는 일관되게 유지되었습니다.
내 이해는 이 두 줄이 동등한 것으로 구문 분석되었지만 분명히 그렇지 않다는 것입니다.
unset debug; $debug && echo stuff
unset debug; && echo stuff
이와 같은 오류로 인해 실패하지 않고 설정되지 않은 변수가 논리적으로 true인 것처럼 코드가 동작하는 이유는 무엇입니까 syntax error near unexpected token `&&'
?
답변1
하지만 확장이 완료된 후에는 구문을 확인하지 않습니다.
$foo
확장 후 생성된 필드 수와 변수 값에 관계없이 구문적으로 유효한 간단한 명령입니다. 확장 전의 쉘 "단어"이면 충분합니다.
쉘이 다른 구문(키워드, 따옴표 등)도 구문 분석할 것으로 예상하는 확장 결과 $foo && whatever
와 동일합니다 . && whatever
아직 완료되지 않았습니다.
그러므로:
foo="then if"
$foo
구문 오류는 아니지만 다음과 같은 일반 명령을 실행해 보십시오 then
(명령이 존재하지 않을 수도 있고 오류가 발생하지만할 수 있다존재하며 "명령을 찾을 수 없음" 오류는 다음과 같습니다.다른then if
하나는 단독으로 실행하려고 하여 발생하는 구문 오류입니다 . ).
그리고:
foo=
$foo
구문 오류는 아니지만 실행하려고 하는데... 뭐, 특별한 경우인 "명령어 이름"이 없어서가 아니라 오류가 아닙니다. 바라보다2.9.1 간단한 명령:
주어진 단순 명령을 실행해야 하는 경우 명령 텍스트의 처음부터 끝까지 다음 확장, 할당 및 리디렉션이 수행됩니다.
[배포, 리디렉션]
변수 할당이나 리디렉션이 아닌 단어는 확장되어야 합니다.만약에확장 후에도 모든 필드는 남아 있습니다. 첫 번째 필드는 명령 이름으로 처리되어야 하며 나머지 필드는 명령에 대한 인수입니다. [...]
"if"에 주의하세요.
명령 이름이 없으면 변수 할당이 현재 실행 환경에 영향을 미치며 명령 대체가 없으면 종료 상태는 0입니다.
따라서 $foo
비어 있거나 설정되지 않은 경우:
$foo
아무것도 하지 않고 종료 상태를 0으로 설정하면 됩니다.
bar=asdf $foo
종료 상태를 0 $bar
으로 설정 하고 0으로 설정합니다. asdf
와 동일 bar=asdf
하지만 $foo
did가 명령 이름으로 확장되면 할당은 해당 명령에만 적용됩니다.
답변2
쉘 명령 언어 사양 섹션에서2.9.1 간단한 명령, 모든 리디렉션, 전역/매개변수 확장 등을 수행한 후:
명령 이름이 있으면 다음에 설명된 대로 실행을 계속해야 합니다.명령어 검색 및 실행. 명령 이름은 없지만 명령에 명령 대체가 포함된 경우 명령은 마지막으로 실행된 명령 대체의 종료 상태로 완료되어야 합니다.그렇지 않으면 명령은 0 종료 상태로 완료되어야 합니다.
당신은 "그렇지 않은 경우" 범주에 속합니다.
답변3
간단한 명령은 할당, 리디렉션 및 인수로 구성됩니다(첫 번째 인수는 실행할 명령을 파생하는 데 사용됩니다).
모두 선택 사항입니다. 인수가 없으면 모든 리디렉션이 수행될 수 있고 리디렉션 및 할당 대상에서 마지막 실행 명령 대체(또는 빈 인수 목록을 생성하는 데 사용된 명령)가 성공하는 한 명령은 성공합니다. 단, IIRC에서는 어떤 리디렉션 및 할당이 지정되어 있지 않습니다. 먼저 마무리하세요.
이 모든 것이 작동했습니다.
a=whatever
: 명령 없음, 리디렉션 없음, 할당만 있음$(true)
: 명령 없음, 리디렉션 없음, 할당 없음, 성공적인 명령 대체 결과는 빈 목록이 됩니다.a=$(false) b=$(true)
.할당만, 마지막 명령이 성공적으로 대체됩니다.> /dev/null
: 명령 없음, 리디렉션 성공> "$(echo /dev/null)"
: 명령 없음, 명령 대체 및 리디렉션 성공empty=; a=foo $empty > /dev/null
:할당 및 리디렉션, 빈 목록이 발생하여 인수/명령이 없는 확장.empty=; $empty
: 위와 동일하며 할당이나 리디렉션이 없습니다.
다음은 실패합니다.
false
a=$(false)
$(false)
> /etc/passwd/foo
< /dev/null"$(false)"
- ...
명시되지 않은:
$(true) > /dev/null$(false)
a=$(false) > /dev/null$(true)
답변4
2개의 명령&&
파이프라인 목록을 결합 하는 연산자 를 고려하십시오 (3.2.4 명령어 목록).
첫 번째 명령은 입니다 $debug
. 변수가 설정되지 않은 경우 명령이 없습니다. 프롬프트에서 Enter를 누르는 것과 마찬가지로 명령이 실행되지 않지만 0이 아닌 종료 상태도 없습니다.
의 왼쪽에는 오류가 없으므로 &&
오른쪽은 자유롭게 실행됩니다.
인용하면 원하는 오류가 발생합니다.
세게 때리다
$ unset debug; $debug && echo hmm hmm $ unset debug; "$debug" && echo hmm bash: : command not found
케시
$ unset debug; $debug && echo hmm hmm $ unset debug; "$debug" && echo hmm ksh: : cannot execute [Is a directory]
스프린트
$ unset debug; $debug && echo hmm hmm $ unset debug; "$debug" && echo hmm dash: 9: : Permission denied