O bash suporta referências anteriores na expansão de parâmetros?

O bash suporta referências anteriores na expansão de parâmetros?

Eu tenho uma variável chamada descrque pode conter uma string Blah: -> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Fooetc. Quero obter a -> r1-ae0-2parte -> s7-Gi0-0-1:1-USda string. No momento eu uso descr=$(grep -oP '\->\s*\S+' <<< "$descr"para isso. Existe uma maneira melhor de fazer isso? Também é possível fazer isso com expansão de parâmetros?

Responder1

ksh93e zshter suporte de referência anterior (ou mais precisamente 1 , referências para grupos de captura na substituição) dentro de ${var/pattern/replacement}, não 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

( mksha página man também menciona que versões futuras irão suportá-lo ${KSH_MATCH[1]}para o primeiro grupo de captura. Ainda não disponível em 25/04/2017).

No entanto, com bashvocê pode fazer:

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

O que é melhor, pois verifica se o padrão foi encontrado primeiro.

Se as expressões regulares do seu sistema suportarem \s/ \S, você também poderá fazer:

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

Com o zsh, você pode obter todo o poder dos PCREs com:

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

Com zsh -o extendedglob, veja também:

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

Portavelmente:

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

Se houver diversas ocorrências do padrão na string, o comportamento irá variar com todas essas soluções. No entanto, nenhum deles fornecerá uma lista separada por nova linha de todas as correspondências, como na sua grepsolução baseada em GNU.

Para fazer isso, você precisa fazer o loop manualmente. Por exemplo, com bash:

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

Com zsh, você poderia recorrer a esse tipo de truque para armazenar todas as correspondências em um array:

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

1 referências anteriores designam mais comumente um padrão que faz referência ao que foi correspondido por um grupo anterior. Por exemplo, a \(.\)\1expressão regular básica corresponde a um único caractere seguido pelo mesmo caractere (corresponde a on aa, não a on ab). Essa \1é uma referência anterior a esse \(.\)grupo de captura no mesmo padrão.

ksh93suporta referências anteriores em seus padrões (por exemplo, ls -d -- @(?)\1listará os nomes de arquivos que consistem em dois caracteres idênticos), não outros shells. BREs e PCREs padrão suportam referências anteriores, mas não ERE padrão, embora algumas implementações de ERE o suportem como uma extensão. bash's [[ foo =~ re ]]usa EREs.

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

não vai combinar, mas

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

pode se os EREs do sistema o suportarem.

Responder2

Você deseja excluir tudo até o primeiro ␣->␣(sem incluir a "seta") e depois do último ␣/(incluindo o espaço e a barra).

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

$stringserá agora -> r1-ae0-2.

As mesmas duas substituições se transformariam -> s7-Gi0-0-1:1-US / Fooem -> s7-Gi0-0-1:1-US.

Responder3

Responder definitivamente é impossível sem saber o formato exatotodomensagem leva. No entanto, como abordagem geral, você pode imprimir determinados campos específicos usando cut:

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

Ou você podeimprima cada enésima coluna usandoawk:

$ 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

informação relacionada