bash의 if 조건에서 정규식 사용


88

bash의 if 절에서 정규 표현식을 사용하는 일반적인 규칙이 궁금합니다.

다음은 예입니다.

$ gg=svm-grid-ch  
$ if [[ $gg == *grid* ]] ; then echo $gg; fi  
svm-grid-ch  
$ if [[ $gg == ^....grid* ]] ; then echo $gg; fi  
$ if [[ $gg == ....grid* ]] ; then echo $gg; fi  
$ if [[ $gg == s...grid* ]] ; then echo $gg; fi  
$   

마지막 3 개가 일치하지 않는 이유는 무엇입니까?

이 예제뿐만 아니라 가능한 한 많은 일반 규칙을 제공 할 수 있기를 바랍니다.

답변:


128

glob 패턴을 사용할 때 물음표는 단일 문자를 나타내고 별표는 0 개 이상의 문자 시퀀스를 나타냅니다.

if [[ $gg == ????grid* ]] ; then echo $gg; fi

정규식을 사용할 때 점은 단일 문자를 나타내고 별표는 0 개 이상의 선행 문자를 나타냅니다. 따라서 " .*"는 0 개 이상의 문자를 a*나타내고 " "는 0 개 이상의 "a [0-9]*"를 나타내고 " "는 0 개 이상의 숫자를 나타냅니다. 또 다른 유용한 기능은 앞의 문자 중 하나 이상을 나타내는 더하기 기호입니다. 따라서 " [a-z]+"는 하나 이상의 소문자 알파 문자를 나타냅니다 (C 로케일 및 다른 일부).

if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi

그래서 문자열 매칭에는 두 가지 방법이 있습니다 : glob 패턴과 정규 표현식? glob pettern은 파일 이름에만 사용되지 않습니까? bash에서 언제 glob 패턴을 사용하고 언제 정규 표현식을 사용합니까? 감사!
Tim

1
@Tim : Globbing은 대부분 또는 모든 버전의 Bash에서 사용할 수 있습니다. 정규식 일치는 버전 3 이상에서만 사용할 수 있지만 3.2 이상에서만 사용하는 것이 좋습니다. 정규식은 글 로빙보다 훨씬 더 다양합니다.
추후 공지가있을 때까지 일시 중지되었습니다.


14
if [[ $gg =~ ^....grid.* ]]

1
"...."대신 ". {4}"를 사용할 수 있어야합니다 (예 : "^. {4} grid. *"). 읽고 이해하기가 더 쉬울 수 있습니다.
user276648

7

더 이식 가능한 솔루션에 관심 이있는 사용자를 위해이 솔루션 grep과 기본 sh내장 기능을 추가합니다 ( bash버전과 무관 하며 일반 오래된 sh, 비 Linux 플랫폼 등에서 도 작동 함 ).

# GLOB matching
gg=svm-grid-ch    
case "$gg" in
   *grid*) echo $gg ;;
esac

# REGEXP    
if echo "$gg" | grep '^....grid*' >/dev/null ; then echo $gg ; fi    
if echo "$gg" | grep '....grid*' >/dev/null ; then echo $gg ; fi    
if echo "$gg" | grep 's...grid*' >/dev/null ; then echo $gg ; fi    

# Extended REGEXP
if echo "$gg" | egrep '(^....grid*|....grid*|s...grid*)' >/dev/null ; then
  echo $gg
fi    

일부 grep화신은 -q로 리디렉션하는 대안으로 (조용한) 옵션 도 지원 /dev/null하지만 리디렉션은 다시 가장 이식성이 좋습니다.


egrep을위한 폐쇄 ")"잊었
ghostdog74

5
사용 grep -q대신에 grep >/dev/null.
bfontaine

3

@OP,

glob pettern은 파일 이름에만 사용되지 않습니까?

아니요, "glob"패턴은 파일 이름에만 사용되는 것이 아닙니다. 문자열을 비교하는데도 사용할 수 있습니다. 예제에서 case / esac을 사용하여 문자열 패턴을 찾을 수 있습니다.

 gg=svm-grid-ch 
 # looking for the word "grid" in the string $gg
 case "$gg" in
    *grid* ) echo "found";;
 esac

 # [[ $gg =~ ^....grid* ]]
 case "$gg" in ????grid*) echo "found";; esac 

 # [[ $gg =~ s...grid* ]]
 case "$gg" in s???grid*) echo "found";; esac

bash에서 언제 glob 패턴을 사용하고 언제 정규 표현식을 사용할까요? 감사!

정규식은 "글롭 패턴"보다 다재다능하고 "편리합니다". 그러나 "글 로빙 / 확장 된 글 로빙"이 쉽게 제공 할 수없는 복잡한 작업을 수행하지 않는 한 정규식을 사용할 필요가 없습니다. 정규식은 bash <3.2 버전에 대해 지원되지 않지만 (dennis 언급했듯이) 확장 된 globbing을 계속 사용할 수 있습니다 (설정에 의해 extglob). 확장 된 글 로빙에 대해서는 여기 와 몇 가지 간단한 예제를 참조하십시오 .

OP 업데이트 : 정규식을 사용하여 2 문자 (점 "."은 1 문자를 의미)와 "g"로 시작하는 파일을 찾는 예

예 : 출력

$ shopt -s dotglob
$ ls -1 *
abg
degree
..g

$ for file in *; do [[ $file =~ "..g" ]] && echo $file ; done
abg
degree
..g

위의 파일 이름에는 "g"가 뒤 따르는 2 개의 문자가 포함되어 있기 때문에 파일이 일치합니다. (예 ..g).

globbing과 동등한 것은 다음과 같습니다. ( 및의 의미 에 대한 참조참조하십시오 )?*

$ for file in ??g*; do echo $file; done
abg
degree
..g

고마워요 ghostdog74. 3.2보다 높은 버전의 Bash에서 후자가 나타날 때마다 정규식을 사용하여 glob 패턴을 대체 할 수 있습니까? 아니면 정규 표현식은 특별한 상황에서만 사용할 수 있습니까? 예를 들어, "ls ?? g"는 작동하지만 "ls ..g"는 작동하지 않습니다.
Tim

필요한 경우 정규식 사용을 중단 할 필요가 없습니다. 그것은 당신에게 달려 있습니다. 정규식 구문은 쉘 글 로빙 구문과 다릅니다. 그래서 ls ..g작동하지 않습니다. 라는 이름의 파일을 찾도록 쉘에 지시 ..g합니다. 정규식 구문에 대한 학습에 관해서는, 당신은 시도 할 수 있습니다 perldoc perlretut, perldoc perlrequick또는을 info sed명령 줄에서.
ghostdog74
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.