`$var && action`을 사용하여 빈 변수를 논리적 "true"로 처리합니다(셸 구문 분석).

`$var && action`을 사용하여 빈 변수를 논리적 "true"로 처리합니다(셸 구문 분석).

특정 명령줄 플래그를 $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 간단한 명령:

주어진 단순 명령을 실행해야 하는 경우 명령 텍스트의 처음부터 끝까지 다음 확장, 할당 및 리디렉션이 수행됩니다.

  1. [배포, 리디렉션]

  2. 변수 할당이나 리디렉션이 아닌 단어는 확장되어야 합니다.만약에확장 후에도 모든 필드는 남아 있습니다. 첫 번째 필드는 명령 이름으로 처리되어야 하며 나머지 필드는 명령에 대한 인수입니다. [...]

"if"에 주의하세요.

명령 이름이 없으면 변수 할당이 현재 실행 환경에 영향을 미치며 명령 대체가 없으면 종료 상태는 0입니다.

따라서 $foo비어 있거나 설정되지 않은 경우:

$foo

아무것도 하지 않고 종료 상태를 0으로 설정하면 됩니다.

bar=asdf $foo

종료 상태를 0 $bar으로 설정 하고 0으로 설정합니다. asdf와 동일 bar=asdf하지만 $foodid가 명령 이름으로 확장되면 할당은 해당 명령에만 적용됩니다.

답변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
    

관련 정보