Ersetzen Sie ein Zeichen in Bash durch ein anderes

223

Ich muss in der Lage sein, ein Leerzeichen ( ) durch einen Punkt ( .) in einer Zeichenfolge in Bash zu ersetzen .

Ich denke, das wäre ziemlich einfach, aber ich bin neu, daher kann ich nicht herausfinden, wie ich ein ähnliches Beispiel für diese Verwendung ändern kann.

Brian Leishman
quelle

Antworten:

390

Verwenden Sie den Inline-Shell-String-Ersatz. Beispiel:

foo="  "

# replace first blank only
bar=${foo/ /.}

# replace all blanks
bar=${foo// /.}

Weitere Informationen finden Sie unter http://tldp.org/LDP/abs/html/string-manipulation.html .

Brian Clapper
quelle
1
Während diese Lösung gut ist, wenn es um kurze Saiten geht (der übliche Fall, denke ich), kann man trlange Saiten bevorzugen . Auf meinem System trübertrifft Bash ab Zeichenfolgen mit mehr als 1000Zeichen. Es scheint, dass die zeitliche Komplexität von bash schlimmer als linear ist. Ein kleiner Test : x="$(tr -dc 'a-z \n' </dev/urandom | head -c1M)"; time y="$(tr ' ' \\- <<< "$x")"; time z="${x// /-}". Mit einer Stringlänge von 1M (= 2 ^ 20) trnahm 0.04sund Bash 5.0.11 nahm 17s. Mit 2M trdauerte 0.07s(erwartet), aber Bash dauerte 69s(4-mal so lang für die doppelte Saitenlänge).
Socowi
@Socowi Das Spielen mit 1 MB in einer Variablen ist nicht wirklich üblich! Bis zu mehr als 10 KB scheint Bash schneller zu bleiben als es trzu tun! ... Abhängig vom verfügbaren Speicher und den Hardware-Ressourcen ... Aber Sie haben Recht!: Je nach Art der zu erledigenden Aufgabe bleiben dedizierte Tools effizienter!
F. Hauri
Suchen Sie für $'\n'
maskierte
75

Sie könnten trwie folgt verwenden:

tr " " .

Beispiel:

# echo "hello world" | tr " " .
hello.world

Von man tr:

BESCHREIBUNG
     Übersetzen, quetschen und / oder löschen Sie Zeichen aus der Standardeingabe und schreiben Sie sie in die Standardausgabe.

aioobe
quelle
Während dies für die gestellte Frage funktioniert, ist es weniger allgemein als die akzeptierte Antwort (die sich auf das Ersetzen von Zeichen und auch auf beliebige Zeichenfolgen bezieht), und es beinhaltet auch einen externen Befehl.
Dan Dascalescu
2
Auf der anderen Seite funktioniert es mit einer 2-GB-Datei, ohne das gesamte Objekt in den Speicher zu laden.
Aioobe
Die Frage betraf "einen String in Bash", keine willkürlich großen Dateien.
Dan Dascalescu
52

In Bash können Sie mit dem Konstrukt Muster in einer Zeichenfolge ersetzen${VARIABLE//PATTERN/REPLACEMENT} . Verwenden Sie nur /und nicht //, um nur das erste Vorkommen zu ersetzen. Das Muster ist wie Platzhalter ein Platzhaltermuster.

string='foo bar qux'
one="${string/ /.}"     # sets one to 'foo.bar qux'
all="${string// /.}"    # sets all to 'foo.bar.qux'
Gilles 'SO - hör auf böse zu sein'
quelle
24

Versuche dies

 echo "hello world" | sed 's/ /./g' 
rauben
quelle
6

Verwenden Sie die Parametersubstitution:

string=${string// /.}
Fritz G. Mehner
quelle
4

Versuchen Sie dies für Pfade:

echo \"hello world\"|sed 's/ /+/g'|sed 's/+/\/g'|sed 's/\"//g'

Es ersetzt das Leerzeichen in der Zeichenfolge in doppelten Anführungszeichen durch ein +Sing, ersetzt dann das +Zeichen durch einen Backslash und entfernt / ersetzt die doppelten Anführungszeichen.

Ich musste dies verwenden, um die Leerzeichen auf einem meiner Pfade in Cygwin zu ersetzen.

echo \"$(cygpath -u $JAVA_HOME)\"|sed 's/ /+/g'|sed 's/+/\\/g'|sed 's/\"//g'
dsrdakota
quelle
2
Es gibt bereits eine zwei Jahre alte Antwort, mit der das Problem gelöst wird sed. Die Anführungszeichen sind irrelevant.
Chepner