작은따옴표 안의 정규식 - 값이 손실되었나요? [폐쇄]

작은따옴표 안의 정규식 - 값이 손실되었나요? [폐쇄]

내가 읽고 있는 책 - 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

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

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

답변2

작은따옴표는 셸에 포함된 문자를 그대로 두도록 지시합니다.설명이 없다. 인용된 문자열은 인용부호 없이 있는 그대로 전달됩니다 grep. grep인수를 검색할 때 다음과 같이 표시됩니다.

grep

그리고

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

그리고 그에 따라 행동하십시오. (읽다프로그램 작동 방식리눅스에서의 매개변수 구성이 궁금하시다면. )

bash그리고 grep그것은 다릅니다. 이 명령은 따옴표를 사용하여 bash문자열이 처리되지 않고 grep문자열이 처리되도록 합니다.

답변3

작은따옴표 방지와일드카드( bash와일드카드를 이렇게 해석하도록 함 *) 그리고 변수 확장을 사용합니다 $. 기본적으로 bash"문자 그대로 이 문자를 가져와서 전달합니다 " 라고 말하는 것입니다 grep. 보시면 grep정규식을 이해할 수 있게 만들어져 있으니그 다음에정규식은 내부적으로 해석됩니다 grep.

더 짧은 버전: 작은따옴표로 묶인 인수는 인수가 명령에 전달되기 전에 셸 처리를 이스케이프하는 방법을 제공합니다.

답변4

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

관련 정보