정규식 특수 제어 문자가 포함된 파일 이름이 있습니다.
문자 그대로 이러한 모든 문자를 고려하는 정규식을 준비해야 합니다.
단순화된 테스트 사례:
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
요약하면, 쉘 변수에 포함된 부분 변수 정규식에 리터럴 문자열을 포함하려면 다음을 수행해야 합니다.
- Perl의 \Q와 \E 대신
\"
and another를 사용하세요 .\"
- 주의 깊게 인용된 내용에 전체 테스트 명령을 포함시킵니다.
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").*";