에코 [[: digit :]]의 예기치 않은 동작


답변:


34

그것들은 서로 다른 두 가지이기 때문입니다. 이것은 괄호 확장{1,2,3} 의 예입니다 . 구조는 확장 하기 전에, 심지어 그것을 본다. 다음을 사용하면 어떻게되는지 볼 수 있습니다 .{1,2,3}echoset -x

$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3

보다시피, 명령 echo {1,2,3}은 다음과 같이 확장됩니다.

echo 1 2 3

그러나 [[:digit:]]A는 POSIX 문자 클래스는 . 당신이 그것을 주면 echo, 쉘은 그것을 먼저 처리하지만 이번에는 쉘 글로 로 처리되고 있습니다 . echo *현재 디렉토리의 모든 파일을 인쇄 하는 것과 같은 방식으로 작동합니다 . 그러나 [[:digit:]]모든 숫자와 일치하는 쉘 글로브입니다. bash에서 쉘 glob가 아무것도 일치하지 않으면 확장됩니다.

$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files

글로브가 무언가와 일치하면 인쇄됩니다.

$ echo /e*c
+ echo /etc
/etc

두 경우 모두 echo쉘이 인쇄하도록 지시 한대로 인쇄하지만, 두 번째 경우 glob이 무언가 ( /etc) 와 일치 하기 때문에 무언가 인쇄하도록 지시됩니다.

따라서 이름이 정확히 하나의 숫자 ( [[:digit:]]일치 하는 숫자)로 구성된 파일이나 디렉토리가 없으므로 glob가 확장되어 다음과 같이 나타납니다.

$ echo [[:digit:]]
[[:digit:]]

이제 파일을 만들고 5동일한 명령을 실행 해보십시오 .

$ echo [[:digit:]]
5

일치하는 파일이 두 개 이상인 경우 :

$ touch 1 5       
$ echo [[:digit:]]
1 5

이것은 이 동작을 끄는 옵션 man bash에 대한 설명에 문서화되어 nullglob있습니다.

nullglob
    If  set,  bash allows patterns which match no files (see
    Pathname Expansion above) to expand to  a  null  string,
    rather than themselves.

이 옵션을 설정 한 경우 :

$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]]  ## prints nothing

$ 

4
또는 shopt -s failglob과 같은 최신 쉘의 동작과 유사한보다 유용한 동작을 얻으려면 참조하십시오 . zshfish
Stéphane Chazelas

나는 Stéphane에 동의합니다 failglob. nullglob가있는 URL을 붙여 넣을 때와 같이 예기치 않은 문제가 발생할 수 있습니다 ?.
Kevin

1
물론, 나는 nullglob패턴이 쉘에 의해 glob로 해석되고 있음을 보여주기 위해 언급 했다.
terdon

14

{1,2,3}이다 중괄호 확장 , 그것은 그 의미에 관계없이 나열된 단어로 확장됩니다.

[...]별표 및 물음표와 유사하게 파일 이름 확장 (또는 와일드 카드 또는 글로브)에 사용되는 문자 그룹 입니다. 내부에 나열된 단일 문자 또는 이름이 지정된 그룹의 구성원 인 문자 (예 : 나열된 문자)와 일치합니다 . 대부분의 쉘의 기본 동작은 와일드 카드와 일치하는 파일이없는 경우 와일드 카드를 그대로 유지하는 것입니다.*?[:digit:]

(와일드 카드 / 패턴을 실제로 일치하는 문자열 세트로 바꿀 수는 없습니다. 별표는 임의의 길이의 문자열과 일치 할 수 있으므로 포함 된 패턴을 확장하면 무한한 문자열 목록이 생성됩니다.)

그래서:

$ bash -c 'echo [[:digit:]]'           # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]'            # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]'           # now there are two matches
1 3                                    # note that d, i, g and t do NOT match

그러나 여전히 :

$ bash -c 'echo {1,2,3}'
1 2 3

둘 다 쉘에 의해 확장되며, 실행중인 명령이 ls, 또는 echo인지 여부는 중요하지 않습니다 rm. 또한 그 중 하나가 인용되면 확장되지 않습니다.

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}

답변 주셔서 감사합니다, 리눅스에
익숙

1
@AbdAllahTalaat 이것은 실제로 에코와 관련이 없습니다. 쉘 (예 : bash는)는이 "확장"됩니다 [[:digit:]] 전에 에 전달하지 echo때문에, echo결코보고 [[:digit:]], 그것은 단지 본다 1 3. set -x실제 실행중인 명령을 인쇄하여 set +x다시 실행 하여 실행 하여이를 확인할 수 있습니다.
terdon

@AbdAllahTalaat, 을 실행하기 전에 echo파일을 찾지 않고 셸에서 찾습니다 echo.
ilkkachu

특히 DOS / Windows에서는 유틸리티가 쉘이 아닌 와일드 카드를 확장한다고 생각합니다. (아마 어쩌면)
ilkkachu

그의 의견은 배쉬가 작업에 반향을 일으키지 않는다는 의미를 포함하고 있기 때문에 그의 답변에 테 트론의 대답으로 올바른 답변을 옮겼습니다 ... 그의 답변도 그 의미를 포함했습니다 .. 모두가 나를 도왔습니다 ... 모든 답변과 의견에 대한 정답
AbdAllah Talaat

4

{1,2,3}(그리고 예를 들면 {1..3}있습니다 중괄호 확장은 . 그들은 명령을 실행하기 전에 쉘에 의해 해석됩니다.

[[:digit:]]패턴 일치 토큰이지만 해당 패턴과 일치하는 파일이있는 위치에서 사용하지 않습니다. 일치하지 않는 패턴 일치를 사용하면 자체적으로 확장됩니다.

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

아니요, 다른 답변에서 올바르게 표시되었으므로 패턴이 파일 이름과 일치합니다.
Toby Speight
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.