grep의 기본/확장 posix 정규식 문자열에서 메타 문자 이스케이프

grep의 기본/확장 posix 정규식 문자열에서 메타 문자 이스케이프

grep에 전달하기 전에 변수 내 문자열의 모든 메타 문자를 이스케이프할 수 있습니까? 이전에도 SE에서 비슷한 질문을 받은 것으로 알고 있습니다(여기) 그리고 좋은 설명여기, 하지만 Perl 패턴 대신 기본/확장 POSIX 정규식 패턴을 사용할 수 있는지 궁금합니다. (현재 저는 솔루션에 뛰어들기보다는 먼저 이해하기 위해 Perl 정규식 구문을 읽고 있습니다.)

이것이 필요한 이유는 무엇입니까?(위안, 답변 필요 없음)

대용량 파일을 분할하기 위한 작은 스크립트를 작성하려고 하는데, 파일을 file_name.ext.000, file_name.ext.001...etc로 분할했는데 훌륭하게 작동합니다. 이제 나는 이미 분할된 파일을 분할하는 것을 좋아하지 않습니다(예: 파일 이름의 확장자는 3자이고 모두 숫자이며 크기의 합은 원래 파일 크기와 같습니다. 이제 file_name.ext.*일반 쉘 확장자를 사용하여 file 이므로 다시 분할할 필요도 없고 전체 크기도 일치하지 않으므로 이름이 숫자 인 file_name.ext.ext2파일만 확인 하고 이러한 부분의 파일 크기를 찾는 현재 표현식은 다음과 같습니다.file_name.ext.######

FILE_SIZE_EXISTING=$( (find "$DESTINATION" -type f -regextype posix-extended -regex "^$DESTINATION/$FILE_BASENAME(\.[[:digit:]]{3})?$" -print0 | xargs -0 stat --printf="%s\\n" 2>/dev/null || echo 0) | paste -sd+ | bc)

이는 간단한 파일 이름에 적용됩니다. 그러나 화려한 이름(예: [ ] 등 포함)이 있는 경우에는 작동하지 않습니다. 해결책이 있나요? 저는 쉘 스크립팅을 처음 접했기 때문에 Perl에 대해 잘 모릅니다.

답변1

특수문자 인용 방법(이식 가능)

다음 코드 조각은 확장된 정규 표현식의 각 특수 문자 앞에 백슬래시를 추가하여 해당 sed문자 중 하나가 나오는 경우 백슬래시와 해당 문자로 바꿉니다.][()\.^$?*+

raw_string='test[string]\.wibble'
quoted_string=$(printf %s "$raw_string" | sed 's/[][()\.^$?*+]/\\&/g')

$raw_string그러면 ;에서 후행 개행 문자가 제거됩니다. 이것이 문제인 경우 끝에 게으른 문자를 추가한 다음 해당 문자를 제거하여 문자열이 개행 문자로 끝나지 않는지 확인하십시오.

quoted_string=$(printf %sa "$raw_string" | sed 's/[][()\.^$?*+]/\\&/g')
quoted_string=${quoted_string%?}

특수 문자를 인용하는 방법(bash 또는 zsh)

Bash와 zsh에는 문자열이 그리 길지 않은 경우 더 빠른 패턴 교체 기능이 있습니다. 교체는 문자열이어야 하므로 각 문자를 별도로 교체해야 하기 때문에 이는 더 번거롭습니다. 먼저 백슬래시를 이스케이프 처리해야 합니다.

quoted_string=${raw_string//\\//\\\\}
for c in \[ \] \( \) \. \^ \$ \? \* \+; do
  quoted_string=${quoted_string//"$c"/"\\$c"}
done

특수 문자를 인용하는 방법(ksh93)

Ksh의 문자열 대체 구성은 bash 및 zsh의 축소된 버전보다 더 강력합니다. 스키마의 그룹에 대한 참조를 지원합니다.

quoted_string=${raw_string//@([][()\.^$?*+])/\\\1}

당신이 정말로 원하는 것이 무엇입니까?

여기서는 필요하지 않습니다 find. 쉘 패턴은 세 자리 숫자로 끝나는 파일을 일치시키는 데 충분합니다. 부품 파일이 존재하지 않으면 glob 패턴이 확장되지 않습니다. 파일 크기를 추가하는 더 쉬운 방법도 있습니다. stat호출할 수 있습니다 (대부분의 시스템에서 파일을 열고 바이트를 읽지 않고도 파일 크기를 확인하는 wc -c일반 파일에서 ).wc

set -- "$DESTINATION/$FILE_BASENAME".[0-9][0-9][0-9]
case $1 in
  *\]) # The glob was left intact, so no part exists
    do_split …;;
  *) # The glob was expanded, so at least one part exists
    FILE_SIZE_EXISTING=$(wc -c "$@" | sed -n '$s/[^0-9]//gp')
    if [ "$FILE_SIZE_EXISTING" -ne "$(wc -c <"$DESTINATION/$FILE_BASENAME")" ]; then
      do_split …
    fi

전체 크기 테스트는 신뢰성이 떨어집니다. 파일이 변경되었지만 크기가 동일하게 유지되면 오래된 부분이 발생하게 됩니다. 파일이 전혀 변경되지 않더라도 괜찮습니다. 유일한 위험은 콘텐츠의 일부가 잘리거나 손실될 수 있다는 것입니다.

관련 정보