nullglob이 기본값이 아닌 이유는 무엇입니까?

nullglob이 기본값이 아닌 이유는 무엇입니까?

이는 대부분의 쉘에서 nullglob기본 설정이 아닙니다 . 이는 예를 들어 이 명령을 실행하면

ls *

빈 디렉토리에서는 빈 인수 목록 대신 *glob을 텍스트로 확장 합니다. 빈 매개변수 목록이 빈 디렉토리에 반환 *되도록 이 동작을 변경하는 방법이 있는데 , 이는 보다 직관적으로 보입니다.*

nullglob그렇다면 기본적으로 비활성화되어 있는 이유가 있나요? 그렇다면 왜 그렇습니까?

답변1

nullglob대부분의 경우 이 옵션은 이상적이지 않습니다. ls좋은 예는 다음과 같습니다.

ls *.txt

또는 더 정확한 표현은 다음과 같습니다.

ls -- *.txt

.txt( 유형을 제외하고 이름이 다음으로 끝나는 파일 나열)목차-d해당 내용이 나열되어 있습니다. 아마도 특별한 대우를 피하기 위해 이 옵션을 사용하려고 할 것입니다.목차문서).

일치하는 파일이 없으면 on은 nullglob인수 없이 실행되며 , 이는 (현재 디렉터리의 내용 나열) ls로 처리되며 , 이는 리터럴을 인수로 호출하는 것보다 나쁠 수 있습니다.ls -- .ls*.txt

대부분의 텍스트 유틸리티에는 비슷한 문제가 있습니다.

grep foo *.txt

foo파일이 없으면 표준 입력으로 검색이 수행됩니다 txt.

csh, tcsh, zsh 또는 Fish 2.3+(및 이전 Unix 쉘)의 기본값인 보다 합리적인 기본값은 glob이 일치하지 않으면 명령을 완전히 취소하는 것입니다.

bash(버전 3부터) 옵션이 있습니다 failglob(이 논의는 ashAT&T 와 달리 ksh또는 반대로 옵션의 로컬 범위를 지원하지 zsh않는 bash3와 달리 전역적으로 활성화되면 bash-completion 기능과 같이 일부 기능이 중단되기 때문에 흥미롭습니다) .

zshcsh와 tcsh는 다음과 같은 경우 fish와 약간 다릅니다 .bash -O failglob

ls -- *.txt *.html

명령을 취소하려면 모든 전역 변수가 일치하지 않아야 합니다. 예를 들어 txt 파일은 있지만 html 파일은 없으면 다음과 같습니다.

ls -- file.txt

with 를 사용하여 이 동작을 얻을 수 있지만 zsh보다 set -o cshnullglob합리적인 접근 방식 zsh은 다음과 같은 glob을 사용하는 것입니다.

ls -- *.(txt|html)

zsh에서도 ksh93신청할 수 있습니다.빈 공전역별로 보면 이는 전역 설정을 수정하는 것보다 더 합리적인 접근 방식입니다.

files=( *.txt(N)  ) # zsh
files=( ~(N)*.txt ) # ksh93

파일이 없으면 txt오류로 인해 명령이 실패하는 대신 빈 배열이 생성됩니다(또는 *.txt다른 셸을 사용하여 하나의 리터럴 인수가 있는 배열로 만듭니다).

fish2.3 이전 버전도 비슷하게 작동했지만 bash -O nullglob상호작용할 때 glob이 일치하지 않으면 경고가 표시되었습니다. 2.3부터는 , zsh또는 에서 사용된 glob과 다르게 작동합니다.forsetcount

역사적으로 이러한 행동은 실제로부서진Bourne 쉘로 구현됩니다. 이전 버전의 Unix에서는 와일드카드 지정이 /etc/glob다음과 같이 작동하는 도우미를 통해 수행 되었습니다 csh. 파일과 일치하는 와일드카드가 없으면 명령이 실패하고, 그렇지 않으면 일치하는 와일드카드가 제거되지 않습니다.

따라서 오늘날 우리가 있는 상황은 Bourne 쉘에서 내린 잘못된 결정 때문입니다.

Bourne 쉘(및 C 쉘)에는 또 다른 새로운 Unix 기능인 환경이 함께 제공됩니다. 이는 변수 확장을 의미합니다(이전 버전에는 $1, $2... 위치 인수만 있었습니다). Bourne 쉘에는 명령 대체도 도입되었습니다.

Bourne 쉘의 또 다른 잘못된 디자인 결정은 변수 확장 및 명령 대체에 와일드카드(및 분할)를 수행하는 것입니다(아마도 와일드카드가 포함된 경우 여전히 호출되는 Thompson 쉘과의 하위 호환성을 위해) echo $1(전처리기 매크로와 비슷함) 확장) 확장 값이 다시 쉘 코드로 구문 분석되므로))./etc/glob$1

예를 들어, 일치하지 않는 실패한 glob은 다음을 의미합니다.

pattern='a.*b'
grep $pattern file

명령이 실패하게 됩니다( a.whateverb현재 디렉터리에 일부 파일이 없는 경우). (변수 확장 시에도 와일드카드를 수행합니다.) 이 경우에는 명령이 실패하게 만듭니다. ( // csh처럼 와일드카드를 전혀 사용하지 않는 것만큼 좋지 않더라도 휴면 오류를 그대로 두는 것보다는 낫다고 생각합니다. .. ).rczshfish


shopt내장 기능은 1996년 2.0에 추가되었으며 , zsh해당 옵션 bash의 이름을 따서 명명되었습니다.allow_null_glob_expansion 바꾸다이전 버전의 경우

² 해당 간격 내에 파일이 생성되지 않았거나 현재 디렉터리가 검색 가능하지만 읽을 수 없고 파일 또는 디렉터리가 존재하지 않는 한 ls파일 없음 오류가 보고될 수 있습니다 . 예를 들어 시도한 후에*.txtmkdir -p '*.txt/wtf'; chmod a=,u=wx .

set -o3 버전 4.4에서는 Almquist 쉘에서처럼 옵션 세트를 로컬 함수로 설정할 수 있지만 두 번째 옵션 세트(옵션 세트 포함)에서는 local -작동하지 않기 때문에 이와 관련하여 약간의 개선이 있었습니다.bashshopt

답변2

nullglob이 디자인은 void 매개변수가 제공될 때 void 결과를 생성하는 명령에 대해 기본값 사용을 고려하여 안전한 접근 방식을 취합니다 . 그러나 이 기본 동작은 다음과 같은 명령에는 적합하지 않을 수 있습니다 ls. 스크립트에서는 유용할 수 있지만 다음과 같은 함수로 대체하지 nullglob않는 한 완전히 안전하지는 않습니다 .ls

myls() { (($#)) && ls "$@" ; }

이렇게 하면 nullglob을 사용할 때 원하는 결과를 얻을 수 있습니다.

shopt -s nullglob
myls empty_directory/*

언어 기본값을 디자인할 때 우선순위는 예상치 못한 동작을 최소화하는 옵션을 채택하는 것입니다. 예측할 수 없는 동작보다 예외를 선호합니다.

nullglob예측할 수 없는 입력 변경이 포함된 복잡한 스크립트를 도입하면 스크립트가 불안정해질 수 있다는 점에 유의하는 것이 중요합니다 . 실제로 이는 좋은 아이디어로 간주될 수 있지만 실제로는 예방 디버깅을 위해 추가 시간이 필요합니다.

관련 정보