쉘 변수에 정규식을 저장하여 쉘 특정 문자를 인용하는 문제를 피하는 방법은 무엇입니까?

쉘 변수에 정규식을 저장하여 쉘 특정 문자를 인용하는 문제를 피하는 방법은 무엇입니까?

~에서배쉬 매뉴얼

쉘 변수에 정규식을 저장하는 것은 쉘 특정 문자를 인용할 때 문제를 방지하는 유용한 방법인 경우가 많습니다.때로는 따옴표를 사용하지 않고 정규식을 문자 그대로 지정하거나 셸의 따옴표 제거에 주의하면서 정규식에서 사용되는 따옴표를 추적하는 것이 어렵습니다.쉘 변수를 사용하여 패턴을 저장하면 이러한 문제를 줄일 수 있습니다.예를 들어 다음은 동일합니다.

pattern='[[:space:]]*(a)?b'
[[ $line =~ $pattern ]]

그리고

[[ $line =~ [[:space:]]*(a)?b ]]

정규식 구문에서 특수 문자를 일치시키려면 특수 문자를 따옴표로 묶어 특수 의미를 제거해야 합니다. 즉 xxx.txt, 패턴 내에서는 .문자열의 모든 문자(일반적인 정규식 의미)와 일치하지만 패턴 내에서는 "xxx.txt"리터럴만 일치할 수 있습니다 .. 셸 프로그래머는 백슬래시에 특별한 주의를 기울여야 합니다. 셸과 정규식 모두 백슬래시를 사용하여 다음 문자의 특별한 의미를 제거하기 때문입니다. 다음 두 명령 세트는 동일하지 않습니다.

pattern='\.'

[[ . =~ $pattern ]]
[[ . =~ \. ]]

[[ . =~ "$pattern" ]]
[[ . =~ '\.' ]]

처음 두 일치는 성공하지만 두 번째 두 일치는 실패합니다. 왜냐하면 후자 두 일치에서는 백슬래시가 일치하는 패턴의 일부가 되기 때문입니다. 처음 두 예에서 백슬래시는 특별한 의미를 제거하므로 .리터럴이 .일치합니다. .예를 들어 첫 번째 예의 문자열이 가 아닌 경우 패턴의 따옴표가 단일 문자와 일치한다는 특별한 의미를 잃기 a때문에 패턴이 일치하지 않습니다 ..

쉘 변수에 정규식을 저장하는 것이 어떻게 쉘 특정 문자를 인용할 때 문제를 방지하는 유용한 방법이 될 수 있습니까?

주어진 예는 이것을 설명하지 못하는 것 같습니다. 주어진 예에서 한 메소드의 정규식 리터럴과 pattern다른 메소드의 쉘 변수는 동일한 값을 갖습니다.

감사해요.

답변1

[[ ... ]]토큰화가 정규식과 충돌합니다(자세한 내용은당신의 후속 질문에 대한 내 대답) 및 \셸 인용 연산자와 정규 표현식 연산자(bash에서 둘 사이에 약간의 간섭이 있음)로 오버로드되며 충돌에 대한 명백한 이유가 없는 경우에도 규칙이 혼란스러울 수 있습니다.

(가능한 모든 입력에 대해) 시도해 보지 않고 특정 버전이 무엇을 할 것인지 누가 알 수 있습니까 bash?

[[ $a = a|b ]]
[[ $a =~ a|b ]]
[[ $a =~ a&b ]]
[[ $a =~ (a|b) ]]
[[ $a =~ ([)}]*) ]]
[[ $a =~ [/\(] ]]
[[ $a =~ \s+ ]]
[[ $a =~ ( ) ]]
[[ $a =~ [ ] ]]
[[ $a =~ ([ ]) ]]

bash 3.2부터 정규식을 인용하면 bash 3.1 호환성이 활성화되지 않은 경우 정규식을 인용하면 RE 연산자의 특별한 의미가 제거되기 때문에 정규식을 인용할 수 없습니다. 예를 들어,

[[ $a =~ 'a|b' ]]

$a텍스트만 포함된 경우 일치합니다 a|b.

정규 표현식을 변수에 저장하면 이러한 모든 문제를 피할 수 있으며 코드가 ksh93및 호환 가능해 집니다 zsh(POSIX ERE로 제한하는 경우).

regexp='a|b'
[[ $a =~ $regexp ]] # $regexp should *not* be quoted.

쉘 명령은 모호함 없이 구문 분석/토큰화되었으며 사용된 정규식은 변환 없이 변수에 저장된 정규식입니다.

답변2

명시적인 문자열을 일치시키는 유일한 방법은 이를 인용하는 것입니다.

[[ $var =~ 'quux' ]]

문자열에 특수 문자(셸에 특수 문자)가 포함된 경우에도[ㅏ])
쉘이 확장하거나 해석하지 않고[비]:

$ var='^abcd'
$ [[ $var =~ '^ab' ]] && echo yes || echo no
yes

실제로 (셸) 특수 문자를 허용하고 셸이 이를 정규식으로 해석하도록 허용하려면 따옴표를 해제해야 합니다.

$ var='abcd'
$ [[ $var =~ ^ab ]] && echo yes || echo no
yes

그러나 따옴표가 없는 문자열은 공백과 같은 새로운 문제를 야기합니다.

$ var='ab cd'
$ [[ $var =~ ^ab cd ]] && echo yes || echo no
bash: syntax error in conditional expression
bash: syntax error near `cd'

이 문제를 해결하려면 특수 문자를 인용해야 합니다.

$ var='ab cd'
$ [[ $var =~ ^"ab cd" ]] && echo yes || echo no
yes

$ [[ $var =~ ^ab\ cd ]] && echo yes || echo no
yes

다른 예:

[[ "a b"  =~  ^a\ b$ ]] && echo yes
[[ "a|b"  =~  ^a\|b$ ]] && echo yes
[[ "a&b"  =~  ^a\&b$ ]] && echo yes

정규식을 변수에 저장하면 이러한 모든 참조 문제를 피할 수 있습니다.

$ regex='^a b$'
$ [[ "a b" =~ $regex ]] && echo yes
yes

[ㅏ] 쉘 특수 문자 목록( | & ; ( ) < > space tab newline).

[비] 이것은 사실이다bash 버전 bash-3.2-alpha 기준("3. Bash의 새로운 기능" 제목 아래):

에프. 이제 다른 패턴 일치 연산자와 마찬가지로 [[ 명령의 =~ 연산자에 대한 문자열 인수를 참조하면 문자열 일치가 강제됩니다.


지원Bash FAQ에 대한 자세한 설명:

E14) 정규식 일치 조건 연산자(=~)에 대한 패턴 인수를 참조하면 정규식 일치가 작동을 중지하는 이유는 무엇입니까?

bash-3.2 이전 버전의 bash에서는 [[ 명령의 =~ 연산자에 대한 정규식 매개변수를 참조하는 효과가 지정되지 않았습니다. 결과적으로 큰따옴표로 묶인 패턴 매개변수에는 특수 패턴 문자를 인용하기 위해 백슬래시가 필요합니다. 이는 큰따옴표로 묶인 단어 확장에 의해 수행되는 백슬래시 처리를 방해하고 == 쉘 패턴 일치 연산자가 따옴표 붙은 문자를 처리하는 방식과 일치하지 않습니다.

bash-3.2에서 쉘은 =~ 연산자의 작은따옴표 및 큰따옴표로 묶인 문자열 인수에서 내부적으로 문자를 인용하도록 변경되었습니다. 이는 정규식 처리('.', '[', '\)에 고유한 문자의 특별한 의미를 억제합니다. ', '(', ')', '*', '+', '?', '{', '|', '^' 및 '$') 문자 그대로 일치하도록 강제합니다. 이는 "==" 패턴 일치 연산자가 패턴 인수의 인용 부분을 처리하는 방식과 일치합니다.

인용된 문자열 매개변수를 처리하는 방식의 변경으로 인해 몇 가지 문제가 발생했습니다. 그 중 가장 큰 문제는 패턴 매개변수의 공백과 bash-3.1과 bash-3.2 사이에서 인용된 문자열의 다른 처리 문제입니다. 두 가지 문제는 쉘 변수를 사용하여 패턴을 저장함으로써 해결될 수 있습니다. [[ 명령의 모든 피연산자에서 쉘 변수가 확장될 때 단어 분리가 수행되지 않으므로 사용자는 변수를 할당할 때 원하는 대로 패턴을 인용한 다음 값을 공백을 포함할 수 있는 단일 문자열로 확장할 수 있습니다. 첫 번째 문제는 백슬래시나 다른 인용 메커니즘을 사용하여 패턴의 공백을 이스케이프 처리함으로써 해결할 수 있습니다.

관련 질문:

정규식에서 변수 사용

관련 정보