제어 문자를 무시하고 정규식(예: 변수)의 일부를 문자 그대로 일치시키려면 어떻게 해야 합니까?

제어 문자를 무시하고 정규식(예: 변수)의 일부를 문자 그대로 일치시키려면 어떻게 해야 합니까?

정규식 특수 제어 문자가 포함된 파일 이름이 있습니다.

문자 그대로 이러한 모든 문자를 고려하는 정규식을 준비해야 합니다.

단순화된 테스트 사례:

strFilenameOnDB="some ( file ) name +.ok";
strFilenameToCheck="$strFilenameOnDB"; #code simplification
strRegex=".*${strFilenameToCheck}.*";
if [[ "$strFilenameOnDB" =~ $strRegex ]];then echo OK;fi

위의 접근 방식은 (물론) 실패할 것입니다.

Perl에서는 /Q /E(https://stackoverflow.com/a/3971923/1422630) 확장된 $strRegex를 리터럴로 변환하려면 bash와 비슷한 것이 있습니까?

Obs.: 이미 하고 있는 일을 게시하겠습니다. 그런데 더 좋은 방법이 있는지 궁금합니다.

답변1

Bash의 =~일치 연산자에서는 큰따옴표로 묶어 정규식에 리터럴 문자열을 지정할 수 있습니다.

따라서 이론적으로는 Perl의 \Q와 \E를 각각 큰따옴표로 변경하기만 하면 됩니다.

그러나 요구 사항이 부분적으로 변경 가능하고(예: 확장할 추가 셸 변수 포함) 부분적으로 리터럴이고 자체적으로 셸 변수에 포함된 정규식을 사용하는 것이라면 유감스럽게도 유일한 방법은 다음과 같습니다.반품사용 eval.

즉, 예제 코드는 다음과 같습니다.

strFilenameOnDB="some ( file ) name +.ok";
strFilenameToCheck="$strFilenameOnDB"; #code simplification
strRegex=".*\"${strFilenameToCheck}\".*";  # <<--- note the backslash before each _inner_ double-quote: this is Bash’s syntax to embed a literal double-quote in a string _made by_ double-quotes

# then we shall use eval on the whole test operation

if eval '[[ "${strFilenameOnDB}" =~ '"${strRegex}"' ]]';then echo OK;fi

# or, using a fine Bash’s shortcut:

eval '[[ "${strFilenameOnDB}" =~ '"${strRegex}"' ]]' && echo OK

요약하면, 쉘 변수에 포함된 부분 변수 정규식에 리터럴 문자열을 포함하려면 다음을 수행해야 합니다.

  1. Perl의 \Q와 \E 대신 \"and another를 사용하세요 .\"
  2. 주의 깊게 인용된 내용에 전체 테스트 명령을 포함시킵니다.eval

정규식을 포함하는 문자열을 확장하려면 이 모든 것이 필요합니다.첫 번째, 두 개의 쉘 변수가 "일반적인 Bash 인용 문자가 아닌 정규식의 리터럴 부분의 시작과 끝으로 처리되고 전체 일치 작업이 결과 패턴에 대해 수행됩니다.

(꼭 포함해야 할 때큰따옴표또는백슬래시큰따옴표로 묶인 쉘 변수 내의 정규식에서 ..)

그건 그렇고, .*정규식의 시작과 끝은 실제로 필요하지 않습니다. 일반적으로 Bash의 정규식 조작에 암시되어 있기 때문입니다. 사실, 당신 ^$아니요정규식 앞뒤에 추가 문자를 암시하고 싶습니다.

답변2

파일 이름에 특정 하위 문자열이 포함되어 있는지 확인하고 싶으신가요? 다음을 사용하면 [[ =~ ]]선행 및 후행 부분이 필요하지 않기 때문에 .*정규식 일치는 다음과 같습니다.찾다, 문자열의 어느 곳에서나 일치하는 항목을 찾는 것으로 충분합니다.

또한 Bash에서 패턴(또는 패턴을 포함하는 변수)을 (부분적으로) 인용하면 인용된 문자의 특별한 의미가 제거됩니다. 예를 들어 다음과 일치합니다.

re=' + '
[[ "foo + doo" =~ "$re" ]] && echo match

그리고 이것은 그렇지 않습니다(더하기 기호는 이제 특별하며 자체적으로 일치하지 않습니다).

re=' + '
[[ "foo + doo" =~ $re ]] && echo match

대조적으로, 비정규식 일치에는 전체 문자열 일치가 필요하므로 선행 및 후행이 필요합니다 *.

pattern=' * '
[[ "foo * doo" = *"$pattern"* ]] && echo match

답변3

개인적으로 나는 리터럴로 원하는 문자열을 정규식 패턴으로 해석하려는 정규식 비트와 결합하지 않을 것입니다. 표현식의 리터럴 문자열 비트는 큰따옴표로 묶어야 하며 정규식으로 해석되어야 하는 비트는 큰따옴표로 묶어서는 안 됩니다.

[[ $strFilenameOnDB =~ .*"$strFilenameToCheck".* ]] && echo OK

하지만 이 경우 기본적으로 정규식은 문자열의 시작이나 끝 부분에 고정되지 않기 때문에 (항상 일치하는 파일 이름 globbing 패턴과 달리)충분히문자열) 측면 공격수가 전혀 없을 수 있습니다 .*.

답변4

매처를 다음과 같이 변경합니다.

sedExact='s"(.)"[\1]"g';
strRegex=".*$(echo "$strFilenameToCheck" |sed -r "$sedExact").*";

관련 정보