배쉬의 역사


11

Bash "globbing"과 정규 표현식이 동일하지 않은 역사적 이유가 있습니까? 예를 들어, Bash [1-2]*에서 1 또는 2로 시작하고 그 뒤에 다른 [1-2]*것이 일치 하는 반면 정규 표현식 은 1과 2의 시퀀스 만 일치한다고 생각합니다. 내 Bash 스크립팅과 REGEX foo는 모두 약하며 정기적으로 이러한 차이점과 관련된 문제가 발생하여 왜 그들이 다른지 궁금했습니다.


3
당신은 일을 고려할 것 rm -- ^[^.].*\.txt$대신에 rm -- *.txt?
Stéphane Chazelas


파일 이름에 대해 작동하고 regexp를 취하는 명령이 있습니다. 예를 들어, 찾기 find . -regex ".*\.txt$" | xargs rm --또는 rename파일 이름 바꾸기 (파일 sed이름)의 경우 일부 시스템의 이름이 다릅니다 rename.
ctrl-alt-delor

@richard, 나는 ^[^.].*\.txt$도트 파일을 무시하는 것을 고려해야했습니다. 참고는 것을 -regex는 GNU 확장 (예를 들어보십시오 : 자신의 globs의에 regexps '에 통합 할 수 있습니다 경우 ksh93 또는 zsh을 같은 일부 포탄입니다 ksh93 -c 'echo ~(E:^[^.].*\.txt$)')
스테판 Chazelas가

2
bash는 기존 관행을 신중하게 따르면서 호환되지 않는 변경 사항과 확장을 피하는 것이 가장 큰 장점 중 하나입니다.
ormaaj

답변:


12

bash80 년대 후반에 kshcsh / tcsh의 일부 대화식 기능 을 갖춘 부분 복제본으로 설계되었습니다 .

globbing의 기원은 그것이 형성되는 초기 껍질에서 찾아야합니다.

ksh그 자체는 Bourne 쉘의 확장입니다. Bourne 쉘 자체 (1979 년 Unix V7에서 처음 릴리스 됨)는 처음부터 완전히 구현되었지만 Thompson 쉘 (V1-> V6의 쉘)에서 완전히 벗어나지 않고 Mashey 쉘의 기능을 통합했습니다.

특히, 명령 인수가 여전히 공백으로 분리되었다가 |이제 새로운 파이프 연산자했지만 ^여전히 대안으로 지원 (그리고 당신이 이유를 설명 [!a-z]하지 [^a-z]), $1여전히 스크립트에 첫 번째 인수했다 및 백 슬래시는 여전히 이스케이프 문자였다 . 많은 정규 표현식 연산자 ( ^\|$)는 쉘에서 자체적으로 특별한 의미를 갖습니다.

Thompson 쉘은 globbing을 위해 외부 유틸리티를 사용했습니다. 때 sh인용 부호가 발견 *, [또는 ?명령에이야, 그것은을 통해 명령을 실행할 것입니다 glob.

rm *.txt

다음과 같이 glob가 실행됩니다.

["glob", "rm", "*.txt"]

glob는 rm해당 패턴과 일치하는 파일 목록으로 실행 됩니다.

grep a.\*b *.txt

다음 glob과 같이 실행 됩니다.

["glob", "grep", "a.\252b", "*.txt"]

*위 의 내용은 해당 문자에 8 번째 비트를 설정하여 인용 glob하여 와일드 카드로 취급하지 않도록 합니다. glob그런 다음 호출하기 전에 해당 비트를 제거합니다 grep.

정규 표현식과 동등한 작업을 수행하려면 다음과 같습니다.

regexp rm '\.txt$'

또는:

regexp rm '^[^.].*\.txt$'

도트 파일을 제외합니다.

셸 특수 문자로 두 배로 증가함에 따라 연산자를 이스케이프 처리해야합니다 .. 파일 이름에서 일반적으로 사용되는 정규 표현식 연산자는 파일 이름을 일치시키는 데 적합하지 않으며 초보자에게는 복잡하지 않습니다. 대부분의 경우 하나 ( ) 또는 임의의 수 ( )의 문자를 대체 할 수있는 와일드 카드 만? 있으면 *됩니다.

이제 다른 쉘은 다른 글러브 연산자를 추가했습니다. 오늘날 ksh 및 zsh glob (및 bash -O extglobksh globs의 하위 집합을 구현하는 정도 )은 파일 이름 및 현재 셸 구문과 함께 사용하기에 덜 성가신 구문을 사용하여 정규 표현식과 기능적으로 동일합니다. 예를 들어 zsh(확장 글로브 확장)에서 다음을 수행 할 수 있습니다.

echo a#.txt

당신이 원하는 경우 (가능성)의 순서로 구성 파일 이름에 맞게 a다음을 .txt. echo (^a*\.txt$)(여기서 쉘이 처리 할 수있는 한 가지 방법 일 수있는 쉘 연산자로부터 정규식 연산자를 분리하는 방법으로 중괄호를 사용하는 것)보다 쉽습니다 .

echo (foo|bar|<1-20>).(#i)mpg

기본 이름이 foo, bar 또는 1에서 20까지의 10 진수 인 mpg 파일 (대소 문자 구분 안 함)의 경우 ...

ksh93이제는 버그에 정규 표현식 (기본, 확장, 펄 유사 또는 "확장")을 통합 할 수 있으며 (글로벌 버그이지만) glob와 regexp ( printf %R, printf %P) 사이를 변환하는 도구를 제공합니다 .

echo ~(Ei:.*\.txt)

와 파일이 txt 일치로 (숨겨지지 않은) E는 , 정규 표현식을 xtended 문자를 구분 전을 nsensitively.


멋진 쓰기! 실제로 ~(opt:pat)대문자 옵션 에는 사용할 수 없습니다 . 아마 print -r -- ~(Ei).*\.txt$. 패턴을 안에 넣는 것은 패턴의 일부에 대해 옵션을 켜고 끄지 않아도되는 데 유용합니다. 이상하게도 같은 글로브 내에서 여러 패턴 언어를 혼합하여 일치시킬 수 있습니다. ~(Ki)*.~(E)txt$동일합니다. (결국 모든 것이 정규식으로 변환되어 libast의 정규식 엔진에 내부적으로 전달됩니다).
ormaaj

@ ormaaj ~(Ei:.*\.txt)는 ksh93 o +와 같은 15 세 이전 버전에서도 작동합니다.
Stéphane Chazelas

저장된 테스트 바이너리 중 하나 (2014-12-24) 와도 작동하지만 문제가 발생한 것을 기억합니다. ksh가 여전히 상업적으로 개발되었을 때 각 버전 사이에서 상황이 항상 임의로 깨지고 다시 고정되었습니다. 패턴 일치 코드가 취약한 영역 중 하나임을 기억합니다.
ormaaj

@ormaaj, ~(E)x그리고 다른 ~(E:x)점은 후자가 고정되어 있다는 것입니다 ( x이전은을 포함하는 모든 항목과 일치하는 경우에만 일치 x). 이는 문제가 발생한 것일 수 있습니다 ( ~(-lr)~(E:x)고정을 제거하는 데 사용 ~(E-lr:x)하지 않음). 어쨌든 최신 버전에서도 버그가 있음을 동의합니다.
Stéphane Chazelas 2016

9

정식 언어 는 1956 년 Kleene 에 의해 소개되었습니다. 정기 간행물 에는 정식 표현에 대한 완전한 현대적 표기법이 없었지만“Kleen star” A*는“모든 반복 횟수”를 의미했습니다 A. 다음 10 년 동안, 특히 .임의의 문자에 대해 다소의 표준 표기법이 나타 났으며 ?, 이전 문자는 선택 사항임을 의미합니다.

Bash의 글 로빙 표기법은 1971 년 Unix v1 에서 다시 도입 된 glob명령 에서 비롯 되었습니다. 그 당시 글 로빙은 별도의 프로그램으로 수행되었습니다. 나중에 껍질로 옮겨졌습니다. 초기 명령은 "모든 문자" 를 의미하고 "모든 문자 시퀀스"를 의미해야합니다. 나는 왜 캐릭터가 선택되었는지 모르겠다. 매우 직관적이며 정규 표현에서 영감을 얻었을 수 있습니다.glob?*?*

글 로빙 (Globbing)은 정규 표현식만큼 일반적이지 않았으며, 당시 정규 표현식은 그다지 널리 퍼지지 않았으므로 개념을 통일 할 필요는 없었습니다. 처음부터로, 구문 호환성이 있었다 ?, .그리고 *파일 이름 패턴과 정규 표현식에서 다른 것을 의미한다.

bash와 같은 최신 쉘은 glob 패턴에서 확장되지만 이전 버전과의 호환성을 유지하면서 점진적으로 발전했습니다. Ksh88는 (의 1988 년 버전의 Korn 쉘 :) 일반적인 정규 표현식과 동일한 구문되지 않을 수도 있지만 강하게 영감을받은 쉘 패턴에 대한 확장 된 구문, 도입 *(PATTERN)의 반복의 수를 의미하는 것으로 PATTERN, @(PATTERN1|PATTERN2)의미 "로 PATTERN1또는 PATTERN2" 기타

bash의 최신 버전 (2.02부터)은 shopt -s extglob먼저 발행하면 ksh88의 확장 패턴을 지원 합니다.


Bash가 extglobs를 지원하지 않았습니까? 내가 아는 한, Bash, zsh 및 {pd, m} ksh는 초기부터 ksh88 매뉴얼에 설명 된 것과 동일한 글로브를 지원했습니다. 현재까지 Ksh에는 "확장 된"glob 정량자를 비활성화 할 수있는 옵션이 없으며, ksh93은 ksh88보다 확장 기능이 뛰어난 유일한 제품입니다.
ormaaj

2
@ormaaj Ksh88 확장 글로브와 extglob옵션은 1998 년경 bash 2.02에서 소개되었습니다. Zsh는 ksh_glob같은시기에 3.1 시리즈에서 인수 했습니다. Zsh에는 자체 확장 기능이 많이 있습니다 (일부 extended_glob옵션이 필요함 ).
Gilles 'SO- 악마 그만해'

내가 참조. 따라서 실제로 옵션의 필요성을 정당화 할만큼 늦었습니다. (저는 기본값이 꺼져있는 것이 요즘 무의미하다고 생각합니다.)
ormaaj

1
@ormaaj, bash와 반대로 kshextglob은 변수에서 비활성화되지 않기 때문에 bash를 POSIX와 호환하지 않습니다. 에서 ksh, var='@(*)'; echo $var로 시작하는 현재 디렉토리에있는 모든 파일 이름 확장 @(과 마지막 )에있는 동안 POSIX의 요구에 따라 bash -O extglob이 파일이 모두로 확장됩니다. (여전히 bash 동작이 더 의미가 있다고 생각할 수 있습니다 (그리고 ksh 동작은 변수에 패턴을 원할 때 상당히 고통 스럽습니다)). 그 globs 구문은 그 때문에 매우 어색합니다 (POSIX / Bourne 호환성). zsh 확장 글로브와 비교하십시오.
Stéphane Chazelas 2016 년

@ StéphaneChazelas이 모든 것이 사실이며, ksh가 다소 영리한 방식이 마음에 듭니다. 실제로 POSIX로 제한되지 않는 한 거의 재생되지 않습니다. IFS를 비워야하기 때문에 어쨌든 단어 분할에 대한 거의 모든 용도가 더 나은 기능으로 대체되고 변수에 패턴을 저장하는 것이 극도의 번거 로움으로 인해 bash 확장 이외의 모든 곳에서 괄호 확장을 비활성화하십시오. 저장된 패턴으로 완전히 안전하는 것은 여전히 ​​불가능하다고 생각합니다. 이 오래된 탈출 문제 는 예를 들어 실제로 해결되지 않았습니다.
ormaaj 2016 년

1

역사적 이유 : 예. 참조 :
http://en.wikipedia.org/wiki/Glob_(programming)#Origin

차이점을 보여주기 위해 다음은 좋은 예입니다. a*

  • 쉘 globbing : 의미는 첫 번째 문자는 a다음에 무엇이든 (a, ab, abca ...)
  • 정규 표현식 : 의미는 0 번 이상의 문자 반복입니다 a(a, aa, aaa ...)

이 불일치가 새로운 사용자에게는 매우 혼란 스럽다는 점에 동의합니다.

글 로빙 (Globbing)은 아마도 새로운 이민자들이 이해하기 쉬울 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.