O que significa “$ {line # * 'Causado por'}”! = “$ line” significa em um script de shell?

7

Alguém pode explicar o que isso significa em um script de shell?

while read -r line
do 
  if [ "${line#*'Caused By'}" != "$line" ]; then
    echo "Yes"
  fi
done       
    
por srikanth chintal 13.02.2018 / 14:45

3 respostas

12

${line#*'Caused By'} é uma instância específica da substituição de variável ${parameter#word} (como está escrito no manual bash , e também no padrão POSIX para o shell sh .

Em ${parameter#word} , o padrão word será removido do início do valor de $parameter . É chamado de "Remover o menor padrão de prefixo" porque removerá a cadeia de caracteres de prefixo menor correspondente ao padrão em word (com ## no lugar de # , remove o maior string de prefixo correspondente).

Neste exemplo específico, a string Caused by (e qualquer coisa anterior, graças ao * ) é, se existir, removida do valor de $line . As aspas simples ao redor da string são redundantes.

Ao comparar o resultado da substituição com o valor da própria variável, o teste determina se o valor de $line contém o texto Caused by e imprime Yes se o fizer.

Isso tem o mesmo efeito que

if [[ "$line" == *'Caused by'* ]]; then
    echo 'Yes'
fi

em bash , ksh93 ou zsh ou

case "$line" in
    *'Caused by'*) echo 'Yes'
esac

em qualquer sh shell.

O loop na pergunta lê "linhas" da entrada padrão. Veja a pergunta " Entendendo" IFS = read -r line " "para uma discussão sobre isso.

    
por 13.02.2018 / 16:39
5

O lado esquerdo da condição if usa o padrão de correspondência funcionalidade do bash. A string correspondente será removida se incluir o 'Caused By'. A linha não será mais idêntica ao que era antes e, portanto, não acionará a cláusula if.

Aqui está um exemplo que você pode executar no shell:

echo -e "Number 1 Caused by me.\nNumber 2 is normal.\n" |
  while read line; do
    echo "${line#*'Caused by'}"
  done

Resultado:

 me.
Number 2 is normal.
    
por 13.02.2018 / 14:57
3

A ação (ou execução neste caso) sempre fala mais alto, então vamos ver o que esse script faz quando executado (desculpe a liberdade tomada para tornar a saída mais detalhada):

while read -r line
do 
  if [ "${line#*'Caused by'}" != "$line" ]; then
    echo "Line contains string Caused by"
  else
    echo "Line does not contain string Caused by"
  fi
done

Input: String with Caused by
Output: Line contains string Caused by
Input: Just a normal string
Output: Line does not contain string Caused by

A correspondência de padrões usada neste script "${line#*'Caused by'} está substituindo todas as cadeias de caracteres (devido ao caractere curinga * ) do início ao fim de Causado por em a linha inserida e, em seguida, compara-a com o parâmetro $line original para ver se são iguais ou não. Simples declarado, tudo o que faz é verificar se a linha contém a string Causada por . Finalmente, ele imprime Linha contém string Causada por se a linha contém Causada por .

Agora, algumas palavras sobre a expansão do parâmetro shell para o formato ${parameter#word} com alguns exemplos:

If the pattern matches the beginning of the value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the "#'' case) or the longest matching pattern (the "##'' case) deleted.

$ test=aabbcc
$ echo ${test#*bb}                                                                    
$ cc

$ test=aabbcc
$ echo ${test#a*b}                                                                    
$ bcc

Um exemplo do formato de padrão de correspondência mais longo:

$ test=aabbcc
$ echo ${test##a*b}                                                                     
$ cc

Referência: man bash : ${parameter#word}

    
por 13.02.2018 / 19:39