bash: Como usar várias manipulações de string (expansão de parâmetro) em uma etapa?

Aug 15 2020

Eu tenho string=substr1-substr2-substr3.substr4onde as substrings são de comprimento variável. Eu quero extrair substr3a partir stringe estou pensando em fazê-lo usando os ${string##pattern}e ${string%pattern}expansões de manipulação de string. Usando essa abordagem, fica claro que preciso executar ${string##*-}e executar ${string%.*}na expansão resultante ou vice-versa. Minhas perguntas são:

  1. esta é a melhor escolha?
  2. Se sim, como faço para executar ambos em uma única etapa? Quando eu tento fazer algo como ${string##*-${string%.*}}ou ${string%.*${string##*-}}simplesmente recupero a string inteira. Percebo que sempre posso fazer a extração em duas etapas atribuindo uma variável intermediária ao resultado da primeira etapa e, em seguida, manipulando isso; mas quero fazer isso em uma etapa. Como proceder?

TIA!

Respostas

2 ilkkachu Aug 15 2020 at 20:39

Dado

string=substr1-substr2-substr3.substr4

${string%.*} é

substr1-substr2-substr3

então ${string##*-${string%.*}}é

${string##*-substr1-substr2-substr3}

o que significa remover desde o início string, tudo até e incluindo -substr1-substr2-substr3. Mas não existe tal substring string, pois não há travessão na frente de substr1, então você obtém a string original.

O que você provavelmente quer é

string=substr1-substr2-substr3.substr4
result="${string%.*}" result="${result##*-}"

o que leva a resultcontaing substr3.

No Zsh, você poderia fazer isso em uma etapa:, mas isso não funciona no Bash.result=${${string%.*}##*-}

No Bash, você está limitado a usar expansões no lado direito de #ou %, e isso não o ajuda aqui, pois você precisa remover partes do início e do final da corda.


Como alternativa, se $stringnão contiver caracteres de nova linha, você pode usar

IFS=.- read -r a b c d <<< "$string"

e ler substr3off partir c.

Nesse caso, dependendo do shell e do tamanho da string, o conteúdo de $stringserá armazenado em um arquivo temporário ou alimentado por um tubo que readirá ler a primeira linha e dividi-la de acordo com $IFS.