작은따옴표 안의 정규식 - 값이 손실되나요?

작은따옴표 안의 정규식 - 값이 손실되나요?

내가 읽고 있는 책 - O'Reilly의 Bash Shell 학습에서는 다음과 같이 일부 코드를 지정합니다.

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

   howmany=$1

   shift
   ....
   ....
   etc

이는 검색 유틸리티를 사용하여 적절한 패턴과 일치하는지 grep테스트합니다 . $1이를 위해 우리는 ^-[0-9][0-9]*$grep에 정규 표현식을 제공합니다. 이는 "초기 대시 다음에 숫자가 오고 선택적으로 하나 이상의 숫자가 뒤따릅니다."로 해석됩니다. 일치하는 항목이 발견되면 grep일치 항목을 반환하고 테스트는 true가 됩니다. 그렇지 않으면 grep아무것도 반환하지 않고 처리가 elif테스트로 전달됩니다.

쉘이 $ 및 *를 해석하는 것을 중지하고 이를 수정되지 않은 상태로 grep에 전달하기 위해 정규식을 작은따옴표로 묶었습니다.

그렇다면 왜 정규식은 '^-[0-9]'작은 따옴표처럼 의미를 잃지 않습니까? 일반적으로 작은 따옴표 안의 모든 내용은 의미를 잃습니다.

도움을 주셔서 감사합니다.

답변1

다른 사람들이 귀하의 특정 질문에 답변했지만 그 점을 추가하겠습니다.

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

여러 가지 이유로 문자열이 정규 표현식과 일치하는지 확인하는 잘못된 방법입니다.

  1. echo임의의 데이터에는 사용할 수 없습니다
  2. 위와 같이 매개변수 확장을 따옴표로 묶지 않은 채로 두면 $1분할+글로브 연산자가 됩니다.
  3. grep정규식을 전체 입력과 일치시키지 않지만 입력의 모든 줄에서 일치합니다. 예를 들어 true를 반환합니다 foo\n-0\nbar.
  4. 정규식은 길이가 0과 일치할 수 있으므로 일반적인 경우 grep출력이 생성되는지 확인하는 것은 잘못된 것입니다(명령 대체는 후행 줄 바꿈 문자를 제거합니다). grep -q의 종료 상태 grep보다는 의 종료 상태를 사용하고 의존하는 것이 더 좋으며 [명령 대체도 피하는 것이 좋습니다.
  5. 해당 grep명령은 다음과 같이 단순화될 수 있습니다.grep -xE '-[0-9]+'

bash, (확장된) 정규식 일치를 위한 전용 연산자가 있습니다 ksh93. zsh세 가지(및 bash-3.1) 모두에서 이식 가능하고 안정적으로 사용하려면 구문은 다음과 같습니다.

re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
  echo matches
fi

yash또한 zsh다음을 지원합니다.

if [ "$1" '=~' '^-[0-9]+$' ]; then
  echo matches
fi

문자열(기본) 정규식 일치를 수행하는 표준 명령은 다음과 같습니다 expr.

if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
  echo matches
fi

^(는 아님 $) 은 에 암시 적으로 포함되어 있습니다 expr. 또한 연산자 $1로 인해 발생하는 값의 문제를 피하기 위해 선행 공백 문자를 사용합니다 expr.

또한 정규식에 가 포함되어 있으면 \(...\)의 동작에 영향을 미칩니다 expr.

전체적으로, awk다른 표준/이식 가능한 방법인 대신 사용하는 것이 더 좋습니다( awk확장 정규 표현식을 사용한다는 점에 유의하세요).

if STRING=$1 RE='^-[0-9]+$' awk '
  BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...

또는 다음 기능을 사용하세요.

re_match() {
  STRING=$1 RE=$2 awk '
    BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}

if re_match "$1" '^-[0-9]+$'

이 경우 표준 case구성을 사용하여 이를 달성할 수도 있습니다.

case $1 in
  ("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
  (*) echo match;;
esac

를 사용하려면 옵션(표준 옵션이 아니기 때문에 지원되는 경우) grep과 함께 사용하여 --null개행으로 구분된 레코드 대신 NUL로 구분된 레코드에서 작동하도록 지시할 수 있습니다. 대부분의 쉘에서는 $1NUL을 포함할 수 없으므로 안전합니다.

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi

답변2

작은 따옴표는 둘러싸는 문자를 그대로 유지하도록 쉘에 지시합니다.아무 해석도 없이. 인용된 문자열은 grep인용부호 없이 있는 그대로 에 전달됩니다 . grep인수를 찾을 때

grep

그리고

^-[0-9][0-9]*$

그리고 그에 따라 행동합니다. (읽다프로그램 실행 방법Linux의 인수 구성에 대해 궁금하신 경우.)

bash그리고 grep다릅니다. 이 명령이 따옴표를 사용하는 방식은 bash문자열을 처리하지 않고 grep처리하도록 보장합니다.

답변3

작은따옴표 방지글로빙( bash와 같은 와일드카드를 해석하도록 허용 *) 및 를 사용하여 변수 확장을 수행합니다 $. 기본적으로 bash"문자 그대로 해당 문자를 가져와 전달 " 한다는 의미입니다 grep. 보면 grep정규표현식을 이해할 수 있도록 만들어졌기 때문에그 다음에정규식은 내부에서 해석됩니다 grep.

더 짧은 버전: 작은따옴표 인수는 인수가 명령에 전달되기 전에 셸에서 처리를 방지하는 수단을 제공합니다.

답변4

그것은 그 의미를 잃습니다. grepbash와 거의 동일한 정규식 패턴을 사용합니다.

관련 정보