Ersetzen einiger Zeichen in einer Zeichenfolge durch ein anderes Zeichen

278

Ich habe eine Zeichenfolge wie AxxBCyyyDEFzzLMN und möchte alle Vorkommen von x , y und z durch _ ersetzen .

Wie kann ich das erreichen?

Ich weiß, dass echo "$string" | tr 'x' '_' | tr 'y' '_'das funktionieren würde, aber ich möchte das auf einmal tun, ohne Rohre zu verwenden.

Amarsh
quelle
Wollten Sie eine Folge aufeinanderfolgender x, y oder z durch einen Unterstrich ersetzen oder wollten Sie jedes x, y oder z durch einen Unterstrich ersetzen ? Und was ist mit gemischten Sequenzen AxyzB? Drei Unterstriche oder einer?
David Z
tr '[xyz]'wird ersetzen [und ]auch. Das Argument sollte einfach eine Liste von Zeichen sein (obwohl Bereiche wie a-zin Ordnung sind und in einigen Implementierungen POSIX-Zeichenklassen wie [:digit:]).
Tripleee

Antworten:

327
echo "$string" | tr xyz _

ersetzen würde jedes Auftreten x, yoder zmit _, was A__BC___DEF__LMNin Ihrem Beispiel.

echo "$string" | sed -r 's/[xyz]+/_/g'

ersetzen würde sich wiederholende Vorkommen x, yoder zmit einem einzigen _, was A_BC_DEF_LMNin Ihrem Beispiel.

jkasnicki
quelle
19
Auf dem Mac habe ich Folgendes erhalten: sed: illegale Option - r Verwendung: sed script [-Ealn] [-i Erweiterung] [Datei ...] sed [-Ealn] [-i Erweiterung] [-e Skript]. .. [-f script_file] ... [file ...]
catanore
Ich habe eine Zeichenfolge, die ,[]{}()~Zeichen enthält . Ich möchte es durch jedes Sonderzeichen ersetzen, das entkommen ist. '\'Wie kann ich dies durch einen Schuss erreichen?
Inckka
2
@halakala Mac wird mit einer etwas anderen Version von sed ausgeliefert. Siehe diese Frage: unix.stackexchange.com/questions/13711/… Stattdessen können Sie "gnu-sed" mit dem Homebrew-Paketmanager installieren und dann die gsedBinärdatei verwenden: $ brew install gnu-sedthen$ gsed -r 's/[xyz]+/_/g'
John Kary
6
Unter * BSD (und damit unter OSX) sed -Eentspricht dies (im Grunde) sed -rvielen Linux-Distributionen. Wenn Sie es verwenden sed 's/[xyz][xyz]*/_/g', benötigen Sie die Option nicht. Dies ist natürlich gleichbedeutend damit, tr -s xyz _dass hier kein wirklicher Bedarf besteht sed.
Tripleee
@inckka Das kannst du nicht verwenden tr. sed 's/[][{}()~,]/\\&/g'Aber wirklich, stellen Sie eine neue Frage, wenn Sie eine Folgefrage haben (zögern Sie nicht, hier als Referenz zurück zu verlinken). Übrigens ,und ~sind keine Regex-Metazeichen (obwohl ~sie $HOMEin einigen Positionen von Bash und einigen anderen Shells erweitert werden; shjedoch nicht ).
Tripleee
285

Verwenden der Bash-Parametererweiterung :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}
Matthew Flaschen
quelle
7
Schlechte Auswechslung
Alexey
1
@Alexey, mein Beispiel funktioniert für mich (Bash 4.3.11 (1) -Veröffentlichung). Stellen Sie sicher, dass Sie verwenden bash. Andere Muscheln funktionieren möglicherweise nicht (obwohl einige dies tun).
Matthew Flaschen
Vielen Dank, dass Sie @MatthewFlaschen. Dies war genau das, was ich brauchte, um einen sed-Ersatz für einen absoluten Pfad in einem Bash-Skript durchzuführen (das Ersetzen des / durch \ / so sed akzeptiert dies).
Ryan G
1
@RyanG warum verwenden, sedwenn bash eine integrierte Substitution hat?
MestreLion
@MestreLion Das mag falsch herausgekommen sein, aber ich musste einen Standardvariablennamen in einer Reihe von Dateien durch einen absoluten Pfad ersetzen, für den ich sed inplace replace verwendet habe. aber Sie können nicht "/" haben, ohne es im Befehl zu entkommen. Ich habe die Operationen in Bash aneinander gereiht. Wäre dies nicht der beste Weg, um einen String in Bash zu manipulieren?
Ryan G
111

Dieser Link könnte hilfreich sein:

http://tldp.org/LDP/abs/html/string-manipulation.html

Allgemein,

So ersetzen Sie die erste Übereinstimmung von $ substring durch $ replace:

${string/substring/replacement}

So ersetzen Sie alle Übereinstimmungen von $ substring durch $ replace:

${string//substring/replacement}

BEARBEITEN: Beachten Sie, dass dies für eine Variable mit dem Namen $ string gilt.

Dylan Daniels
quelle
16
Beachten Sie, dass dies für eine Variable mit dem Namen "string" funktioniert, nicht für die Literalzeichenfolge.
Mattdm
1
das hilfreichste, da es Referenz enthält.
Os3
Beste und kürzeste Lösung.
Nordbaum
8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ Verwenden Sie so viele davon, wie Sie benötigen, und Sie können Ihre eigene BASIC-Verschlüsselung erstellen

Michael
quelle
5

Hier ist eine Lösung mit Shell-Parametererweiterung, die mehrere zusammenhängende Vorkommen durch ein einziges ersetzt _:

$ var=AxxBCyyyDEFzzLMN
$ echo "${var//+([xyz])/_}"
A_BC_DEF_LMN

Beachten Sie, dass für das Muster ein erweiterter Mustervergleich erforderlich ist, der mit aktiviert ist+(pattern)

shopt -s extglob

Alternativ mit der -sOption ("Squeeze") von tr:

$ tr -s xyz _ <<< "$var"
A_BC_DEF_LMN
Benjamin W.
quelle