bash는 매개변수 확장 시 역참조를 지원합니까?

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"이것을 사용하고 있습니다. 더 좋은 방법이 있나요? 매개변수 확장을 통해서도 이를 수행할 수 있습니까?

답변1

ksh93대신 zsh역참조(더 정확하게는 대체 항목의 캡처 그룹에 대한 참조)에 대한 내부 지원 이 있습니다 .${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

( mksh매뉴얼 페이지에는 향후 버전이 ${KSH_MATCH[1]}첫 번째 캡처 그룹을 지원할 것이라고 언급되어 있습니다. 이는 2017년 4월 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

문자열에서 패턴이 여러 번 발생하는 경우 이러한 모든 솔루션은 다르게 동작합니다. 그러나 그 중 어느 것도 grepGNU 기반 솔루션처럼 개행으로 구분된 모든 일치 목록을 제공하지 않습니다.

이렇게 하려면 수동으로 반복해야 합니다. 예를 들어 다음과 같습니다 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동일한 패턴의 캡처링 그룹에 대한 역참조입니다.\(.\)

ksh93해당 모드에서는 역참조를 지원하지만(예: ls -d -- @(?)\1두 개의 동일한 문자로 구성된 파일 이름이 나열됨) 다른 쉘에서는 지원하지 않습니다. 역참조는 표준 BRE 및 PCRE에서 지원되지만 표준 ERE에서는 지원되지 않습니다. 단, 일부 ERE 구현에서는 이를 확장으로 지원합니다. ERE를 사용 bash합니다 [[ foo =~ re ]].

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

어울리지는 않겠지만

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

시스템의 ERE가 지원한다면 가능합니다.

답변2

␣->␣첫 번째 항목 ("화살표" 제외)과 마지막 항목 (공백 및 슬래시 포함) ␣/이후의 모든 항목을 제거하려고 합니다 .

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.

답변3

정확한 형식을 알지 못하면 이 질문에 명확하게 대답하는 것은 불가능합니다.모든메시지가 필요합니다. 그러나 일반적인 접근 방식으로 다음을 사용하여 일부 특정 필드를 인쇄할 수 있습니다 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

관련 정보