web-dev-qa-db-de.com

extrahiere einen Teil eines Strings mit bash / cut / split

Ich habe eine Zeichenfolge wie diese:

/var/cpanel/users/joebloggs:DNS9=domain.com

Ich muss den Benutzernamen (joebloggs) aus dieser Zeichenfolge extrahieren und in einer Variablen speichern.

Das Format der Zeichenfolge ist mit Ausnahme von joebloggs und domain.com Immer dasselbe. Ich denke also, die Zeichenfolge kann mit cut zweimal geteilt werden.

Die erste Aufteilung würde durch : Aufgeteilt und wir würden den ersten Teil in einer Variablen speichern, um ihn an die zweite Aufteilungsfunktion zu übergeben.

Die zweite Aufteilung würde durch / Aufgeteilt und das letzte Wort (joebloggs) in einer Variablen speichern

Ich weiß, wie man das in PHP mit Arrays und Splits macht, aber ich bin ein bisschen in Bash verloren.

92
Craig Edmonds

So extrahieren Sie joebloggs aus dieser Zeichenfolge in Bash mithilfe der Parametererweiterung ohne zusätzliche Prozesse ...

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.com" 

NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

Hängt nicht davon ab, dass sich joebloggs in einer bestimmten Tiefe des Pfades befindet.


Zusammenfassung

Eine Übersicht einiger Parametererweiterungsmodi als Referenz ...

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

Damit # bedeutet Übereinstimmung von Anfang an (denken Sie an eine Kommentarzeile) und % bedeutet vom Ende. Eine Instanz bedeutet die kürzeste und zwei Instanzen die längste.

Sie können Teilzeichenfolgen basierend auf der Position mithilfe von Zahlen abrufen:

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

Sie können bestimmte Zeichenfolgen oder Muster auch ersetzen, indem Sie Folgendes verwenden:

${MYVAR/search/replace}

Das pattern hat dasselbe Format wie der Dateinamenabgleich, also * (beliebige Zeichen) ist gebräuchlich, häufig gefolgt von einem bestimmten Symbol wie / oder .

Beispiele:

Bei einer Variablen wie

MYVAR="users/joebloggs/domain.com" 

Entfernen Sie den Pfad, der den Dateinamen verlässt (alle Zeichen bis zu einem Schrägstrich):

echo ${MYVAR##*/}
domain.com

Entfernen Sie den Dateinamen und verlassen Sie den Pfad (löschen Sie die kürzeste Übereinstimmung nach dem letzten /):

echo ${MYVAR%/*}
users/joebloggs

Holen Sie sich nur die Dateierweiterung (entfernen Sie alle vor dem letzten Zeitraum):

echo ${MYVAR##*.}
com

HINWEIS: Um zwei Operationen auszuführen, können Sie diese nicht kombinieren, sondern müssen sie einer Zwischenvariablen zuweisen. So erhalten Sie den Dateinamen ohne Pfad oder Erweiterung:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain
261
beroe

Definiere eine Funktion wie diese:

getUserName() {
    echo $1 | cut -d : -f 1 | xargs basename
}

Und übergeben Sie die Zeichenfolge als Parameter:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName
35

Was ist mit sed? Das funktioniert mit einem einzigen Befehl:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • Die Zeichenfolge # Wird für Regex-Teiler anstelle von / Verwendet, da die Zeichenfolge / Enthält.
  • .*/ Erfasst den String bis zum letzten Backslash.
  • \( .. \) markiert eine Erfassungsgruppe. Dies ist \([^:]*\).
    • Das [^:] Sagt ein beliebiges Zeichen _ausgenommen einen Doppelpunkt, und das * Bedeutet null oder mehr.
  • .* Steht für den Rest der Zeile.
  • \1 Bedeutet ersetzen, was in der ersten (und einzigen) Erfassungsgruppe gefunden wurde. Das ist der Name.

Hier ist die Aufschlüsselung, die den String mit dem regulären Ausdruck vergleicht:

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'
18
David W.

Mit einem einzigen sed

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'
10
Yann Moisan

Verwenden einer einzelnen Awk:

... | awk -F '[/:]' '{print $5}'

Das heißt, wenn Sie als Feldtrennzeichen entweder / Oder : Verwenden, befindet sich der Benutzername immer in Feld 5.

So speichern Sie es in einer Variablen:

username=$(... | awk -F '[/:]' '{print $5}')

Eine flexiblere Implementierung mit sed, bei der der Benutzername nicht Feld 5 sein muss:

... | sed -e s/:.*// -e s?.*/??

Das heißt, löschen Sie alles von : Und darüber hinaus und löschen Sie dann alles bis zum letzten /. sed ist wahrscheinlich auch schneller als awk, daher ist diese Alternative definitiv besser.

9
janos