명령줄에서 정규식 백슬래시를 이스케이프하는 데 필요한 백슬래시 수

명령줄에서 정규식 백슬래시를 이스케이프하는 데 필요한 백슬래시 수

최근 명령줄에서 일부 정규식을 사용하는 데 문제가 있었고 백슬래시를 일치시키기 위해 다른 수의 문자를 사용할 수 있다는 것을 발견했습니다. 숫자는 정규식에 사용되는 따옴표(없음, 작은따옴표, 큰따옴표)에 따라 달라집니다. 무슨 뜻인지 보려면 다음 bash 세션을 참조하세요.

echo "#ab\\cd" > file
grep -E ab\cd file
grep -E ab\\cd file
grep -E ab\\\cd file
grep -E ab\\\\cd file
#ab\cd
grep -E ab\\\\\cd file
#ab\cd
grep -E ab\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\\cd file
grep -E "ab\cd" file
grep -E "ab\\cd" file
grep -E "ab\\\cd" file
#ab\cd
grep -E "ab\\\\cd" file
#ab\cd
grep -E "ab\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\\cd" file
grep -E 'ab\cd' file
grep -E 'ab\\cd' file
#ab\cd
grep -E 'ab\\\cd' file
#ab\cd
grep -E 'ab\\\\cd' file

이는 다음을 의미합니다.

  • 따옴표 없이 하나의 백슬래시를 4-7개의 실제 백슬래시와 일치시킬 수 있습니다.
  • 큰따옴표를 사용하면 백슬래시를 3~6개의 실제 백슬래시와 일치시킬 수 있습니다.
  • 작은따옴표를 사용하면 백슬래시를 2~3개의 실제 백슬래시와 일치시킬 수 있습니다.

내가 아는 한, 쉘은 추가 백슬래시를 무시합니다(bash 매뉴얼 페이지에 있음).

"따옴표가 없는 백슬래시(\)는 이스케이프 문자입니다. 뒤에 오는 다음 문자의 리터럴 값을 유지합니다."

작은 따옴표에서는 이스케이프가 수행되지 않기 때문에 작은 따옴표 예제에서는 작동하지 않습니다.

grep 명령은 추가 백슬래시를 무시합니다("\c"는 단지 "c" 이스케이프이지만 "c"는 정규식에서 특별한 의미가 없으므로 "c"와 동일합니다).

이것은 작은따옴표가 있는 예제의 동작을 설명하지만 다른 두 예제, 특히 따옴표가 없는 큰따옴표 문자열 사이에 차이가 있는 이유를 잘 이해하지 못합니다.

Bash 매뉴얼 페이지에서 다시 인용하려면 다음을 수행하십시오.

"문자를 큰따옴표로 묶으면 기록 확장이 활성화된 경우 $, `, \ 및 !를 제외한 따옴표 안의 모든 문자의 리터럴 값이 보존됩니다."

나는 GNU awk(예를 들어)를 사용하여 동일한 awk /ab\cd/{print} file결과를 얻었습니다.

그러나 Perl은 다른 결과를 보여줍니다(예: 사용 perl -ne "/ab\\cd/"\&\&print file).

  • 따옴표가 없으면 백슬래시를 4-5개의 실제 백슬래시와 일치시킬 수 있습니다.
  • 큰따옴표를 사용하면 백슬래시를 3~4개의 실제 백슬래시와 일치시킬 수 있습니다.
  • 작은따옴표를 사용하면 하나의 백슬래시와 2개의 실제 백슬래시를 일치시킬 수 있습니다.

grep 및 awk 명령줄에서 따옴표가 없는 정규식 문자열과 큰따옴표로 묶인 정규식 문자열의 차이점을 설명할 수 있는 사람이 있나요? 나는 일반적으로 Perl의 한 줄을 사용하지 않기 때문에 Perl의 동작에 대한 설명에는 별로 관심이 없습니다.

답변1

인용되지 않은 예의 경우 각 \\쌍은 하나의 백슬래시를 grep에 전달하므로 4개의 백슬래시는 grep에 두 개의 백슬래시를 전달하며 이는 단일 백슬래시로 변환됩니다. 6개의 백슬래시는 3을 grep에 전달합니다. 이는 1개의 백슬래시로 변환되고 1은 \c과 같습니다 c. 백슬래시가 하나 더 있어도 쉘 \c->로 변환되므로 아무 것도 변경되지 않습니다. c셸의 백슬래시 8개는 grep의 4개이며 이는 2개로 변환되므로 더 이상 일치하지 않습니다.

큰따옴표로 묶인 예의 경우 bash 매뉴얼 페이지의 두 번째 인용문 다음에 나오는 내용을 참고하세요.

백슬래시는 $, `, ", \ 또는 개행 문자 중 하나가 뒤에 오는 경우에만 특별한 의미를 유지합니다.

즉, 홀수 개의 백슬래시를 제공하면 시퀀스는 로 끝나며 \c이는 unquoted c와 같지만 인용되면 백슬래시는 특별한 의미를 잃어 \cgrep으로 전달됩니다. 이것이 "가능한" 백슬래시(즉, 예제 파일과 일치하는 패턴을 구성하는 백슬래시)의 범위가 하나씩 줄어든 이유입니다.

답변2

이 링크는 bash를 설명합니다인용문과 탈출

귀하의 질문은 처음 세 부분과 관련이 있습니다.

  • 각 문자를 탈출
  • 약한 참조 "큰따옴표"
  • 강력한 참조 '아포스트로피'
  • ANSI C와 유사한 문자열 참조
  • I18N/L10N 인용(국제화 및 현지화).

아래 다이어그램은 문자열이 bash문자열 주위로 전달되는 방식 grepgrep내부적으로 추가로 해석되는 방식을 보여줍니다.

먼저 살펴보겠습니다 echo "#ab\\cd" > file.
내부에약한 참조("") 는 이스케이프이며 "#ab\\cd"단일 리터럴로 전달됩니다. 그러므로 그것은 다음을 포함합니다 \\\file\fileab\cd

이제 명령을 따르십시오. 아래 다이어그램은 각 호출에서 실제로 무슨 일이 일어나고 있는지 이해하는 데 도움이 될 수 있습니다. *파일 내용과 일치하는 내용을 표시합니다 . 웹 페이지에서와 마찬가지로 bash의 이스케이프 규칙을 적용하고 다음에 특별한 주의를 기울이면 됩니다.다니엘 콜먼의그가 언급한 회피 행동에 대한 반응으로약한 참조상태.

백슬래시는 $, `, ", \ 또는 개행 문자 중 하나가 뒤에 오는 경우에만 특별한 의미를 유지합니다.


                            bash passes    grep further
                            to grep        resolves to         
grep -E ab\cd file            abcd           abcd   
grep -E ab\\cd file           ab\cd          abcd  
grep -E ab\\\cd file          ab\cd          abcd
grep -E ab\\\\cd file         ab\\cd         ab\cd    * 
grep -E ab\\\\\cd file        ab\\\cd        ab\cd    *
grep -E ab\\\\\\cd file       ab\\\cd        ab\cd    *    
grep -E ab\\\\\\\cd file      ab\\\cd        ab\cd    *
grep -E ab\\\\\\\\cd file     ab\\\\cd       ab\\cd

grep -E "ab\cd" file          ab\cd          abcd
grep -E "ab\\cd" file         ab\cd          abcd
grep -E "ab\\\cd" file        ab\\cd         ab\cd    *
grep -E "ab\\\\cd" file       ab\\cd         ab\cd    *
grep -E "ab\\\\\cd" file      ab\\\cd        ab\cd    *
grep -E "ab\\\\\\cd" file     ab\\\cd        ab\cd    *
grep -E "ab\\\\\\\cd" file    ab\\\\cd       ab\\cd    

grep -E 'ab\cd' file          ab\cd          abcd  
grep -E 'ab\\cd' file         ab\\cd         ab\cd    *
grep -E 'ab\\\cd' file        ab\\\cd        ab\cd    *
grep -E 'ab\\\\cd' file       ab\\\\cd       ab\\cd

관련 정보