Bash 정규식에서 다음과 같은 비대칭 예제를 발견했는데, 이는 나를 혼란스럽게 합니다. 내가 하고 있는 일이 비표준적이어서 이 동작을 일으키는지, 또는 내가 누락한 이 동작 뒤에 있는 논리가 무엇인지 알고 싶습니다.
파일을 열다
file1.txt
이라는 파일이 포함된 디렉토리가 있다고 가정해 보겠습니다 file20.txt
. 즐겨 사용하는 텍스트 편집기에서 해당 파일을 열고 싶습니다. 이를 위해 Bash는 어떤 의미에서 디렉터리의 내용을 "읽고" Vim에 전달해야 합니다. 이를 달성하기 위해 다음 정규식을 사용할 수 있습니다.
vim file{[1-9],1[0-9],20}.txt
이것은 작동합니다. 이 명령을 실행하면 Vim이 열리고 버퍼 목록 file1.txt
에 file20.txt
.
파일 만들기
이제 우리가 다른 시나리오에 있다고 상상해 보십시오. 빈 디렉토리로 시작 file1.txt
하여 file20.txt
. 불행하게도 이 경우에는 이전 명령이 작동하지 않습니다. 필요한 20개의 파일을 만드는 대신 버퍼 목록에 다음 파일이 생겼습니다.
file[1-9].txt
file[0-9].txt
file20.txt
[]
따라서 대괄호가 정규식의 일부로 해석되는 대신 이름에 통합되었습니다.
읽고 쓸 때 왜 이러한 비대칭이 발생합니까? 앞으로 이런 일을 어떻게 피할 수 있습니까?
답변1
정규식을 사용하지 않고 조합을 사용하고 있습니다.버팀대 확장그리고파일 이름 확장(일명 와일드카드). 중괄호 확장은 단순히 구문이 포함된 문자열을 { ... }
여러 다른 문자열로 확장하는 반면 와일드카드 부분은 실제로 다음을 시도하기 때문에 이는 중요합니다.기존 파일을 패턴과 일치. 문제는 다음과 같습니다. (그런데 정규 표현식도 다음 용도로 사용됩니다.기존 문자열을 패턴과 일치, 패턴을 기반으로 문자열을 생성하지 않습니다).
특히 중괄호 확장은 파일 이름 확장 전에 수행된다는 점에 유의하세요.
그래서
file{[1-9],1[0-9],20}.txt
셸에서 공백으로 구분된 세 개의 토큰으로 확장됨
file[1-9].txt file1[0-9].txt file20.txt
그런 다음 실제 파일 이름 확장이 적용됩니다. 여기서 쉘은 어떤 파일이 무엇인지 확인합니다.이 glob 패턴과 일치하는 기존 파일. 중요한 점은 패턴 중 하나와 일치하는 파일이 없으면문자 그대로 패턴을 취함.
그럼 열면 어떻게 될까요?
vim file{[1-9],1[0-9],20}.txt
로 확장됩니다vim file[1-9].txt file1[0-9].txt file20.txt
vim file[1-9].txt file1[0-9].txt file20.txt
vim file1.txt file2.txt ... file20.txt
때문에 확장됩니다 .이 파일은 모두 존재합니다(그럴 것이다아니요해당 숫자 범위 내에 존재하지 않는 파일로 확장됩니다)vim
이 파일을 모두 엽니다.
그러나 touch
예를 들어 동일한 매개변수를 사용하는 경우존재하지 않는 파일을 생성하세요., 무슨 일이 일어나는지
touch file{[1-9],1[0-9],20}.txt
로 확장됩니다touch file[1-9].txt file1[0-9].txt file20.txt
- 패턴과 일치하는 파일이 없으므로
[1-9]
,1[0-9]
및20
유지됩니다.문자 그대로 touch
문자 그대로 이름이 지정된 세 개의 파일을 만듭니다.
이를 방지하고 해당 범위의 모든 파일을 생성하려면 명령줄을 중괄호 확장으로 제한하면 됩니다.
touch file{1..20}.txt
(pLumo의 의견에서도 지적됨)
참고로(@Quasimodo가 제안함) bash
및 기타 여러 쉘에서 글로빙 동작을 다음과 같이 조정할 수 있습니다.주택 옵션, bash
특정 용도로.shopt -s option
이 옵션은 여기서 특히 흥미롭습니다 nullglob
. 왜냐하면 쉘이 패턴 리터럴을 그대로 두지 않고 빈 문자열에 파일 이름과 일치하지 않는 와일드카드 패턴을 확장하게 하기 때문입니다. 이는 루프를 사용하여 패턴과 일치하는 모든 파일을 반복하려는 경우 특히 유용합니다 for
.
- 아니요옵션
nullglob
, 양식 루프
한 번 실행되고for f in *.txt
$f
다음으로 설정됩니다.단어*.txt
현재 디렉터리에 파일이 없으면.txt
예기치 않은 동작(예: 존재하지 않는 파일에서 작동하려는 코드)이 발생할 수 있습니다. - 그리고이
nullglob
옵션을 사용하면 쉘이 루프 본문에 전혀 들어가지 않습니다.
반면에(@Barmar가 올바르게 지적했듯이) stdin
파일에 "None"으로 평가되는 glob 패턴을 제공하면 파일 이름이 일치하지 않기 때문에 파일에서 작동하는 많은 프로그램이 자동으로 읽기를 시도하므로 이것을 사용합니다. 옵션을 주의하지 않으면 이상한 부작용이 발생할 수 있습니다.
또한 nullglob
Bash에는 failglob
일치하지 않는 glob이 있는 경우 명령을 실행하는 대신 오류를 표시하는 옵션이 있습니다.