명령줄에서는 테스트가 실패했지만(올바른) 스크립트에서는 성공했습니다(잘못됨)

명령줄에서는 테스트가 실패했지만(올바른) 스크립트에서는 성공했습니다(잘못됨)

이 문제를 해결하려면 glob이 /a/b/c/*일치하는 항목을 생성하지 않는다고 가정합니다.

이는 다음 테스트가 실패해야 함을 의미합니다(즉, 0이 아닌 값을 생성해야 함 $?).

[[ -n /a/b/c/*(#qN) ]]

실제로 이런 경우가 있습니다만약에(zsh) 명령줄에서 직접 테스트를 실행합니다. 하지만 내가 계속한다면완전 똑같은 테스트스크립트에서는 예상되는 동작이 아닌 성공합니다.

해당 플래그를 사용하여 동일한 스크립트를 실행하면 -x결과 추적에 테스트가 다음과 같이 표시됩니다.

[[ -n '/a/b/c/*(#qN)' ]]

테스트 매개변수 주위에 작은 따옴표가 나타나는 이유를 이해할 수 없습니다. 스크립트 소스 코드에는 따옴표가 전혀 없습니다.

zsh가 이러한 작은따옴표를 자동으로 삽입하면 텍스트가 성공한 이유가 설명됩니다.

질문:

  1. 이 표현식의 명령줄 버전과 스크립트 버전 간에 차이가 있는 이유는 무엇입니까?
  2. 스크립트의 테스트가 (올바르게) 실패하도록 하려면 어떻게 해야 합니까?

답변1

CONDITIONAL EXPRESSIONSzsh 매뉴얼 의 섹션:

어떤 형태의 조건부 인수에서도 파일 이름 생성이 수행되지 않습니다. 그러나 일반 셸 확장이 적용되고 EXTENDED_GLOB 옵션이 적용되는 경우 문자열 끝에 (#q) 형식의 명시적 glob 한정자를 사용하여 이를 강제로 적용할 수 있습니다.

즉, 스크립트 내에서 extendedglob옵션이 설정되지 않은 경우 /a/b/c/*(#qN)리터럴 문자열로 처리됩니다.

답변2

glob이 파일과 일치하는지 확인하는 더 나은 관용구(IMO)는 다음과 같습니다.

()(($#)) /a/b/c/*(NY1)

extendedglob여기에는 특별한 상황이 필요하지 않습니다 [[ -n ...(#qN) ]]. 그리고 Y1첫 번째 플레이에서 멈추기 때문에 더 효율적입니다.

(($#))이는 익명 함수에 인수 수가 0이 아닌 경우 true를 반환하는 산술 표현식 인 익명 함수에 glob 확장을 전달하는 방식으로 작동합니다 .

이를 다음과 같이 확장할 수 있습니다.

if ()(( $# >= 3 )) /a/b/c*(NY3); then
  echo there were at least 3 matching files.
fi

관련 정보