Extrahieren einer Zeichenfolge nach einem Muster in einem Bash-Skript

17

Angenommen, ich habe eine Zeichenfolge strname:

strname="ph7go04325r"

Ich möchte die Zeichen zwischen dem ersten "3" und dem letzten "r" Zeichen in extrahieren und strnamedas Ergebnis in einer Zeichenfolge speichern strresult. Im obigen Beispiel strresultwäre das Ergebnis :

strresult="25"

Das erste "3"Zeichen muss sich nicht unbedingt an der Zeichenfolgeposition 8 in befinden strname. ebenfalls der letzte "r"ist nicht an Saitenlage notwendigerweise 11. Somit können sowohl der folgenden Zeichenketten strnameergeben sollten strresult="25":

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

Auch strname=ph12go04330raa"sollte nachgeben strresult="30".

Ich bin neu im Bash-Scripting und weiß nicht, wo ich anfangen soll, einen solchen String-Pattern-Matching durchzuführen. Hast du irgendwelche Vorschläge?

Andrew
quelle

Antworten:

28

Sie können einen regulären Ausdruck in bash (3.0 oder höher) verwenden, um dies zu erreichen:

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

In bash werden Erfassungsgruppen aus einem regulären Ausdruck in das spezielle Array eingefügt BASH_REMATCH. Element 0 enthält die gesamte Übereinstimmung, und 1 enthält die Übereinstimmung für die erste Erfassungsgruppe.

Jordanien
quelle
10

In der Standardsyntax sh(würde also mit jeder Version bashoder jeder anderen POSIX-kompatiblen Shell funktionieren) würden Sie Folgendes tun:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

Siehe auch die alte exprLösung, die auch auf 35 Jahre alten Unices funktioniert:

expr "x$strname" : 'x[^3]*3\(.*\)r'

Das alte Manko bei exprist, dass Sie, wenn die Übereinstimmung fehlschlägt, einen Nicht-Null-Beendigungsstatus (in Ordnung) erhalten, aber auch einen Nicht-Null-Beendigungsstatus, wenn die zurückgegebenen Zeichenfolgen in 0 aufgelöst werden (wie bei strname=zz300rzz).

Stéphane Chazelas
quelle
Ich denke, Ihre Formulierung impliziert fälschlicherweise, dass dies nur mit älteren Versionen von bash möglich ist. Die Parametererweiterung ist in modernen Schalen natürlich immer noch ein guter Ansatz.
Kojiro
1
@kojiro, ich verstehe, was du meinst. Die anfängliche Formulierung bestand darin, die Antwort von Jordan weiterzuverfolgen. Ich habe meine Antwort aktualisiert.
Stéphane Chazelas