Was bedeutet "$ {line # * 'Caused By'}"! = "$ Line" in einem Shell-Skript?

7

Kann jemand erklären, was dies in einem Shell-Skript bedeutet?

while read -r line
do 
  if [ "${line#*'Caused By'}" != "$line" ]; then
    echo "Yes"
  fi
done       
Srikanth Chintal
quelle

Antworten:

12

${line#*'Caused By'}ist eine bestimmte Instanz der Variablensubstitution ${parameter#word}(wie im bashHandbuch und auch im POSIX-Standard für die shShell beschrieben).

In ${parameter#word}wird das Muster wordvom Anfang des Wertes von entfernt $parameter. Es heißt „entfernen Kleinste Präfix - Muster“ genannt , weil es den Entfernen kürzesten passende Präfix - String nach dem Muster in word(mit ##anstelle von #dem entfernt längsten passenden Präfix - String).

In diesem speziellen Beispiel wird die Zeichenfolge Caused by(und alles, was davor liegt, dank der *), falls vorhanden, aus dem Wert von entfernt $line. Die einfachen Anführungszeichen um die Zeichenfolge sind redundant.

Durch Vergleichen des Ersetzungsergebnisses mit dem Wert der Variablen selbst ermittelt der Test, ob der Wert von $lineden Text enthält Caused by, und druckt, Yesfalls dies der Fall ist.

Dies hat den gleichen Effekt wie

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

in bash, ksh93oder zsh, oder

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

in jeder shSchale.


Die Schleife in der Frage liest "Zeilen" von der Standardeingabe. Eine Diskussion hierzu finden Sie in der Frage " IFS = read -r line " verstehen .

Kusalananda
quelle
6

Die linke Seite der if-Bedingung verwendet die Pattern Matching- Funktionalität von bash. Die übereinstimmende Zeichenfolge wird entfernt, wenn sie die 'Verursacht von' enthält. Die Zeile ist nicht mehr identisch mit der vorherigen und löst daher nicht die if-Klausel aus.

Hier ist ein Beispiel, das Sie auf der Shell ausführen können:

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

Ergebnis:

 me.
Number 2 is normal.
Stefan M.
quelle
3

Aktion (oder Ausführung in diesem Fall) spricht immer lauter. Schauen wir uns also an, was dieses Skript bei der Ausführung tut (entschuldigen Sie die Freiheit, die Ausgabe ausführlicher zu gestalten):

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

Der in diesem Skript verwendete Mustervergleich "${line#*'Caused by'}ersetzt alle Zeichenfolgen (aufgrund des Platzhalters *) vom Anfang bis zum Ende von Caused by in der eingegebenen Zeile und vergleicht sie dann mit dem ursprünglichen $lineParameter, um festzustellen, ob sie gleich sind oder nicht. Einfach ausgedrückt, alles, was es tut, ist eine Überprüfung, ob die Zeile die Zeichenfolge Caused by enthält . Schließlich wird gedruckt. Zeile enthält Zeichenfolge Verursacht durch, wenn die Zeile Verursacht durch enthält .

Nun ein paar Worte zur Shell-Parametererweiterung für das ${parameter#word}Format mit einigen Beispielen:

Wenn das Muster mit dem Anfang des Parameterwerts übereinstimmt, ist das Ergebnis der Erweiterung der erweiterte Parameterwert mit dem kürzesten Übereinstimmungsmuster (Fall "#") oder dem längsten Übereinstimmungsmuster (Fall "##") ) gelöscht.

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

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

Ein Beispiel für das am längsten übereinstimmende Musterformat:

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

Referenz: man bash :${parameter#word}

Neugierig
quelle
Verstanden, danke für die Klarstellung! Bearbeiten der Antwort, um über $ {parameter # word} zu sprechen
Neugierig
@ Jesse_b kannst du es jetzt bitte überprüfen?
Neugierig
Scheint richtig, aber nicht viel anders als Kusalanandas Antwort.
Jesse_b