[unix] bash는 매개 변수 확장에서 역 참조를 지원합니까?

나는라는 변수가 descr문자열을 포함 할 수 있습니다 Blah: -> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo등 내가 싶어 -> r1-ae0-2, -> s7-Gi0-0-1:1-US문자열에서 일부를. 현재 나는 이것을 위해 사용 descr=$(grep -oP '\->\s*\S+' <<< "$descr"합니다. 더 좋은 방법이 있습니까? 매개 변수 확장으로이 작업을 수행 할 수도 있습니까?



답변

ksh93zsh백 레퍼런스 (또는보다 정확하게이 하나 의 여분의 포획 기 참조) 지지체 내부는 ${var/pattern/replacement},하지 bash.

ksh93:

$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2

zsh:

$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2

( mkshman 페이지는 또한 향후 버전이 ${KSH_MATCH[1]}첫 번째 캡처 그룹 을 위해 이를 지원할 것이라고 언급하고 있습니다 ( 2017-04-25 기준).

그러나을 사용 bash하면 다음을 수행 할 수 있습니다.

$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
  printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2

패턴이 먼저 발견되는지 확인하는 것이 좋습니다.

시스템의 정규 표현식이 \s/를 지원하는 경우 다음 \S을 수행 할 수도 있습니다.

re='->\s*\S+'
[[ $var =~ $re ]]

을 사용 zsh하면 다음을 통해 PCRE의 모든 기능을 활용할 수 있습니다.

$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2

로 다음 zsh -o extendedglob을 참조하십시오.

$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2

포터블 :

$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2

문자열에 패턴이 여러 번 나타나는 경우 모든 솔루션에 따라 동작이 달라집니다. 그러나 그중 어느 것도 GNU grep기반 솔루션 에서와 같이 줄 바꿈으로 구분 된 모든 일치 목록을 제공하지 않습니다 .

그렇게하려면 손으로 루핑을해야합니다. 예를 들어,에 bash:

re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
  printf '%s\n' "${BASH_REMATCH[1]}"
  var=${BASH_REMATCH[2]}
done

을 사용하면 zsh모든 일치 항목을 배열에 저장하는 이러한 종류의 트릭을 사용할 수 있습니다.

set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches

1 역 참조는 이전 그룹과 일치하는 것을 참조하는 패턴을 더 일반적으로 지정합니다. 예를 들어, \(.\)\1기본 정규 표현식은 단일 문자 다음에 동일한 문자가옵니다 (on aa이 아니라 on ab). 이는 동일한 패턴 \1으로 해당 \(.\)캡처 그룹에 대한 역 참조 입니다.

ksh93ls -d -- @(?)\1다른 셸이 아닌 패턴에서 역 참조를 지원합니다 (예 : 두 개의 동일한 문자로 구성된 파일 이름을 나열 함). 표준 BRE 및 PCRE는 역 참조를 지원하지만 표준 ERE는 지원하지 않지만 일부 ERE 구현에서는이를 확장으로 지원합니다. bash[[ foo =~ re ]]사용의 ERES을.

[[ aa =~ (.)\1 ]]

일치하지 않지만

re='(.)\1'; [[ aa =~ $re ]]

시스템의 ERE가이를 지원한다면


답변

첫 번째 ␣->␣( “화살표”제외) 및 마지막 ␣/(공백 및 슬래시 포함 ) 까지 모든 항목을 삭제하려고합니다 .

string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}

$string이제 것 -> r1-ae0-2입니다.

같은 두 개의 대체가 될지는 -> s7-Gi0-0-1:1-US / Foo으로 -> s7-Gi0-0-1:1-US.


답변

모든 메시지 의 정확한 형식을 모른 채 확실하게 대답하는 것은 불가능 합니다. 그러나 일반적인 방법으로 다음을 사용하여 특정 필드를 인쇄 할 수 있습니다 cut.

$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US

또는 다음을 사용하여 모든 n 번째 열을 인쇄awk 할 수 있습니다 .

$ awk -F' ' '{ for (i=2;i<=NF;i+=4) print $i }' <<< '-> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo'
r1-ae0-2
s7-Gi0-0-1:1-US


답변