Wie ersetze ich einen Teilstring aus einer Variablen?

7

Ich versuche, Zeichen aus einer Zeichenfolgenvariablen zu entfernen. Es funktioniert bei mir sedso:

MYVAR=--23ho02123ware38384you443d34o3434ingtod38384day-%§*#sfrf
echo ${MYVAR} | sed -e 's/[a-z][a-z0-9\-]*//g'

und ich bekomme:

 --23%§*#

das ist was ich suche. Die Zeichenfolge sollte mit einem Buchstaben beginnen und nur Buchstaben, Ziffern und einen Bindestrich (-) enthalten. Gibt es eine Möglichkeit, dies durch bashErsetzen von Zeichenfolgen zu erreichen ?

MYVAR=${MYVAR/[a-z][a-z0-9-]*/ }

Ich habe mehrere Kombinationen ausprobiert, aber keine davon funktioniert wie erwartet.

Dings
quelle
Das Ersetzen von Bash-Strings unterstützt KEINEN regulären Ausdruck! Beim Ersetzen von Bash-Strings wird Globbing ausgeführt, wobei * gleich * in Regex ist. check en.wikipedia.org/wiki/Glob_(programming)
frams

Antworten:

10

Sie müssten die erweiterten ksh-Glob-Operatoren (von denen eine Teilmenge in bashwith shopt -s extglobund with zshwith verfügbar ist set -o kshglob) verwenden, um das Äquivalent regulärer Ausdrücke zu erhalten (allerdings mit einer anderen Syntax: *(x)für das Äquivalent von x*hier):

shopt -s extglob # for bash
# set -o kshglob # for zsh
printf '%s\n' "${MYVAR//[[:alpha:]]*([[:alnum:]-])/}"

Oder mit zsh extendedglobs, wo das Äquivalent von regulärem Ausdruck *ist #:

set -o extendedglob
printf '%s\n' ${MYVAR//[[:alpha:]][[:alnum:]-]#}

Ein paar Anmerkungen:

  • ${var/pattern/replacement}ersetzt nur das erste Vorkommen. Verwenden ${var//pattern/replacement}jedes Vorkommen zu ersetzen (wie mit der gFahne in sed‚s - sBefehl).
  • Sie hatten Ihren Ersatz zu einem Leerzeichen gemacht. Verwenden Sie ${var//pattern/}(oder ${var//pattern}), um durch die leere Zeichenfolge zu ersetzen.
  • Sie möchten keine echobeliebigen Zeichenfolgen ausgeben
  • Außer in zshmüssen Variablenerweiterungen in Listenkontexten in Anführungszeichen gesetzt werden
  • Das Verhalten würde sich von Ihrem sedAnsatz unterscheiden, wenn die Variable Zeilenumbrüche enthält.
  • [a-z]Übereinstimmungen, die zwischen Zeichen (Elemente in einigen Werkzeugen Kollationieren) aund zdie Liste der sich ändert mit den Lokalisierungs, das System und das Werkzeug (beispielsweise [a-z]mit bash-4.3in einem en_GB.UTF-8locale auf einem GNU System entspricht A, X, é, , aber nicht Z). Dies schließt im Allgemeinen die 26 Kleinbuchstaben des englischen Alphabets ein, muss aber nicht. [[:alpha:]]Enthält Zeichen (oder Sortierelemente), die in Ihrem Gebietsschema als alphabetisch (unabhängig von der Groß- und Kleinschreibung) betrachtet werden. Wenn Sie nur mit den 26 englischen Buchstaben übereinstimmen möchten, verwenden [abcdefghijklmnopqrstuvwxyz]oder korrigieren Sie das Gebietsschema auf C( LC_ALL=C) und verwenden Sie [a-z]oder nur [[:lower:]]für englische Kleinbuchstaben oder [a-zA-Z]/[[:alpha:]] für jeden englischen Brief.
  • [a-z0-9\-]in sedstimmt mit dem Backslash-Zeichen überein, verwenden Sie [a-z0-9-]stattdessen (das -muss das erste oder letzte sein, um wörtlich genommen zu werden).
Stéphane Chazelas
quelle
könnte auch hinzufügen, dass //für gFlag im Gegensatz zu /von OP verwendet wird, äquivalent ist und dass das letzte Leerzeichen in OPs Versuch das übereinstimmende Muster durch Leerzeichen ersetzt
Sundeep
1
Vielen Dank Stéphane Chazelas, es funktioniert wie ein Zauber, auch ohne die erweiterten ksh-Glob-Operatoren shopt -s extglob. Best
dings
KORREKTUR: shopt extglob war auf meinem Computer bereits aktiviert, also brauche ich es wirklich!
Nochmals
schöne Erklärung! Ich habe das Leerzeichen in meinem Ersatz gesehen, das ich bereits korrigiert habe. Ich verwende das Gebietsschema en_US.UTF-8 auf dem System, exportiere aber de_DE.UTF-8, wenn ich das Skript ausführe, um europäische Buchstaben in ASCII-Zeichen konvertieren zu können, da en_US.UTF-8 sie nicht korrekt konvertiert. Neue Zeilenzeichen sind kein Problem, da diese Zeichenfolge eine Benutzeranmeldung ist, die in der Bash-Eingabeaufforderung eingegeben wurde. Dies ist Teil eines riesigen Skripts, das ich geschrieben habe, um LDAP-Konten auf zwei verschiedenen Servern zu erstellen, und ich versuche, das Skript zu zwingen, nur gültige Formatanmeldungen zu akzeptieren. Vielen Dank.
Dings
1
@Sundeep, guter Punkt. Ich habe jetzt diese Notizen und ein paar mehr aufgenommen.
Stéphane Chazelas