대괄호가 쉘 확장을 방지하는 이유는 무엇입니까?

대괄호가 쉘 확장을 방지하는 이유는 무엇입니까?

"4800483343"은 디렉터리이고 "file1"과 "file2"는 그 안에 있는 두 개의 파일입니다.

왜 다음과 같은 상황이 발생합니까?

$ ls 4800483343
file1 file2

$ md5sum 4800483343/*
36468e77d55ee160477dc9772a99be4b  4800483343/file1
29b098f7d374d080eb006140fb01bbfe  4800483343/file2

$ mv 4800483343 4800[48]3343

$ md5sum 4800[48]3343/*
md5sum: 4800[48]3343/*: No such file or directory

$ md5sum '4800[48]3343'/*
36468e77d55ee160477dc9772a99be4b  4800[48]3343/file1
29b098f7d374d080eb006140fb01bbfe  4800[48]3343/file2

이 문제를 일으킬 수 있는 다른 문자는 무엇입니까?

답변1

원래 질문에 답하다

대괄호가 쉘 확장을 방지하는 이유

대괄호는 쉘 확장을 방지하지 않지만 따옴표는 방지합니다.

실제로 실행한 명령은 다음과 같았을 것 같습니다.

그러면 다음 파일에서 md5sum이 실행됩니다 dir/.

$ md5sum d[i]r/*
02fdd7309cef4d392383569bffabf24c  dir/file1
db69ce7c59b11f752c33d70813ab5df6  dir/file2

그러면 대괄호가 확장되지 않도록 따옴표가 dir이동 됩니다.d[i]r

$ mv dir 'd[i]r'

dir더 이상 존재하지 않는 디렉토리를 찾습니다 .

$ md5sum d[i]r/*
d[i]r/*: No such file or directory

따옴표로 인해 다음 항목은 다음 이름의 새 디렉터리에서 찾을 수 있습니다 d[i]r.

$ md5sum 'd[i]r'/*
02fdd7309cef4d392383569bffabf24c  d[i]r/file1
db69ce7c59b11f752c33d70813ab5df6  d[i]r/file2

수정된 질문에 답하세요

수정된 질문에는 디렉터리 4800483343이 존재하며 다음 명령이 실행됩니다.

mv 4800483343 4800[48]3343

이 명령을 실행할 때 발생하는 일은 glob이 4800[48]3343기존 디렉터리와 일치하는지 여부에 따라 다릅니다. 일치하는 디렉터리가 없으면 4800[48]3343자체적으로 확장되고 4800[48]3343디렉터리 4800483343를 디렉터리로 이동합니다 4800[48]3343.

마침내:

  1. 이 명령은 md5sum 4800[48]3343/* glob과 일치하는 디렉터리가 없기 때문에 "해당 파일 또는 디렉터리가 없습니다"라는 오류를 반환합니다 4800[48]3343.

  2. 따옴표가 전역 확장을 방지하므로 이 명령은 md5sum '4800[48]3343'/*파일을 올바르게 찾습니다.

글로벌 예시

두 개의 파일을 만들어 보겠습니다.

$ touch a1b a2b

이제 다음 구체를 살펴보십시오.

$ echo a[123]b
a1b a2b
$ echo a?b
a1b a2b
$ echo *b
a1b a2b

답변2

대괄호 표현식은 임의의 수를 나타냅니다.하나의가능한 일치 문자하나의캐릭터 위치. 이 간단한 경험 법칙은 멀티바이트 문자와 [[.조합 요소 .]]및/또는 동등 클래스를 처리하기 시작할 때 흐려지는 경향이 있지만 그럼에도 불구하고 아직 이러한 문자에 대한 다중 문자 일치를 완전히 지원하지 않는 프로그램이 많이 있습니다. 모든 로케일에 대해 ASCII 숫자 0-9는 항상 일치하며 대괄호 표현식 내에서 순서대로 정렬됩니다. POSIX에서는 적어도 마지막 숫자가 참이어야 합니다.[[==]]

예를 들어:

cd /tmp
for d in 0 1 2 3 4 5 6 7 8 9; do mkdir "$d"; done
ls [0123]

0:

1:  

2:

3:

기본적으로 단일 [대괄호 표현식 ]쉘 glob은 보다 구체적인 ?char glob입니다.

echo ?/; echo [2468]/

0/ 1/ 2/ 3/ 4/ 5/ 6/ 7/ 8/ 9/
2/ 4/ 6/ 8/

따라서 쉘 glob은 4800[48]3343다음 두 개의 현재 디렉터리 파일 이름 중 하나와 일치합니다.

480043343
480083343

...근데 안 어울릴 것 같아...

4800483343
4800843343
4800[48]3343

파일 이름에 리터럴 대괄호를 사용하려면 대괄호 표현식에서 대괄호를 일치시킬 수 있습니다.

touch 4800\[48]3343
echo 4800[[]48[]]3343

4800[48]3343

쉘의 대괄호 와일드카드에도 따옴표가 너무 많이 필요하지 않습니다. 쉘은 목록 컨텍스트에서 glob 표현식의 시작으로 세 문자를 인식합니다.

* ? [

왼쪽 대괄호가 없는 오른쪽 대괄호는 또 다른 문자일 뿐이므로 인용할 필요가 없습니다.

echo ]

]

따라서 쌍의 여는 괄호만 인용하면 항상 문자 그대로 해석됩니다. 그렇지 않으면 언제든지 와일드카드를 완전히 비활성화할 수 있습니다.

set -f

여가 시간에 다시 켜십시오.

set +f

답변3

4800483343디렉터리 이름 을 로 바꾸면 메타 문자를 이스케이프하기 위해 인용 형식을 사용해야 4800[48]3343합니다 . [ ]이것은 모두 작동합니다:

$ ls 4800\[48\]3343/*
$ ls "4800[48]3343"/*
$ ls '4800[48]3343'/*

모두 올바르게 인쇄됩니다.

4800[48]3343/file1  4800[48]3343/file2

그러나 메타 문자를 유지 [하고 ]따옴표 없이 그대로 두면 "경로 이름 확장"에 대한 대괄호 설명으로 해석됩니다. bash 매뉴얼에서 "경로 이름 확장"을 검색하면 다음을 찾을 수 있습니다.

[...]는 포함된 문자 중 하나와 일치합니다.

이것이 어떻게 작동하는지 설명하는 텍스트가 더 있습니다. 간단히 말해서:

A [abc] will match ONE character, either an `a`, an `b` or an `c`.

따라서 따옴표가 없는 경우 또는 와 4800[48]3343일치합니다 . 그 중 어느 것도 디렉토리가 아니며 : 디렉토리가 없기 때문에 확장되지 않습니다 . 더 복잡한 확장은 디렉터리와 일치하며 확장이 작동합니다.480043343480083343
4800[48]3343ls 4800[48]3343/*

$ ls 4800$'\133'[48][48]$'\135'3343/*

하지만 어쩌면 나는 여기서 주제에 너무 깊이 들어가고 있을지도 모릅니다. :-)

관련 정보