it-swarm.com.de

Suchen und Ersetzen in einer Textdatei mit einem Bash-Befehl

Was ist die einfachste Möglichkeit, eine bestimmte Eingabezeichenfolge zu suchen und zu ersetzen, z. B. abc, und durch eine andere Zeichenfolge zu ersetzen, z. B. XYZ in der Datei /tmp/file.txt?

Ich schreibe eine App und verwende IronPython, um Befehle über SSH auszuführen - aber ich kenne Unix nicht so gut und weiß nicht, wonach ich suchen soll.

Ich habe gehört, dass Bash nicht nur eine Befehlszeilenschnittstelle ist, sondern auch eine sehr mächtige Skriptsprache sein kann. Wenn dies zutrifft, können Sie vermutlich solche Aktionen ausführen.

Kann ich das mit bash machen und was ist das einfachste (einzeilige) Skript, um mein Ziel zu erreichen?

502
Ash

Der einfachste Weg ist sed (oder Perl) zu benutzen:

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

Wodurch sed aufgerufen wird, um eine direkte Bearbeitung aufgrund der Option -i durchzuführen. Dies kann von Bash aufgerufen werden.

Wenn Sie wirklich nur bash verwenden möchten, kann Folgendes funktionieren:

while read a ; do echo ${a//abc/XYZ} ; done < /tmp/file.txt > /tmp/file.txt.t ; mv /tmp/file.txt{.t,}

Dies durchläuft jede Zeile, führt eine Ersetzung durch und schreibt in eine temporäre Datei (die Eingabe soll nicht überlastet werden). Die Verschiebung am Ende wird nur vorübergehend auf den ursprünglichen Namen verschoben.

839
johnny

Die Dateimanipulation wird normalerweise nicht von Bash ausgeführt, sondern von Programmen, die von Bash aufgerufen werden, z.

> Perl -pi -e 's/abc/XYZ/g' /tmp/file.txt

Das -i -Flag weist es an, einen direkten Austausch durchzuführen.

Siehe man perlrun für weitere Einzelheiten, einschließlich der Vorgehensweise zum Erstellen einer Sicherungskopie der Originaldatei.

157
Alnitak

Ich war überrascht, weil ich darüber gestolpert bin ...

Es gibt einen "replace" Befehl, der im Lieferumfang des Pakets "mysql-server" enthalten ist. Wenn Sie ihn also installiert haben, probieren Sie ihn aus:

# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt

# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"

Siehe man replace für mehr dazu ...

66
rayro

Dies ist ein alter Beitrag, aber für alle, die Variablen verwenden möchten, wie @centurian sagte, bedeuten die einfachen Anführungszeichen, dass nichts erweitert wird.

Ein einfacher Weg, um Variablen in zu bekommen, ist die Verkettung von Strings, da dies durch Nebeneinanderstellen in bash geschehen kann. Folgendes sollte funktionieren:

sed -i -e 's/'"$var1"'/'"$var2"'/g' /tmp/file.txt

41
zcourts

Bash ist wie andere Shells nur ein Werkzeug zum Koordinieren anderer Befehle. Normalerweise würden Sie versuchen, Standard-UNIX-Befehle zu verwenden, aber Sie können natürlich Bash verwenden, um alles aufzurufen, einschließlich Ihrer eigenen kompilierten Programme, anderer Shell-Skripten, Python und Perl-Skripten usw.

In diesem Fall gibt es verschiedene Möglichkeiten.

Wenn Sie eine Datei lesen und in eine andere Datei schreiben möchten, verwenden Sie sed:

sed 's/abc/XYZ/g' <infile >outfile

Wenn Sie die Datei direkt bearbeiten möchten (als ob Sie die Datei in einem Editor öffnen, bearbeiten und dann speichern möchten), geben Sie dem Zeileneditor 'ex' Anweisungen.

echo "%s/abc/XYZ/g
w
q
" | ex file

Ex ist wie vi ohne den Vollbildmodus. Sie können ihm die gleichen Befehle geben, die Sie bei der Eingabeaufforderung von vi ':' ausführen würden.

38
slim

Fand diesen Thread unter anderem und ich bin damit einverstanden, dass er die vollständigsten Antworten enthält, also füge ich auch meinen hinzu:

1) sed und ed sind so nützlich ... von hand !!! Schauen Sie sich diesen Code von @Johnny an:

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

2) Wenn meine Einschränkung die Verwendung durch ein Shell-Skript ist, kann keine Variable anstelle von abc oder XYZ verwendet werden! This scheint mit dem übereinzustimmen, was ich zumindest verstehe. Also kann ich nicht verwenden:

x='abc'
y='XYZ'
sed -i -e 's/$x/$y/g' /tmp/file.txt
#or,
sed -i -e "s/$x/$y/g" /tmp/file.txt

aber was können wir tun? Wie, @Johnny sagte, benutze ein 'while read ...', aber das ist leider nicht das Ende der Geschichte. Folgendes hat bei mir gut funktioniert:

#edit user's virtual domain
result=
#if nullglob is set then, unset it temporarily
is_nullglob=$( shopt -s | egrep -i '*nullglob' )
if [[ is_nullglob ]]; then
   shopt -u nullglob
fi
while IFS= read -r line; do
   line="${line//'<servername>'/$server}"
   line="${line//'<serveralias>'/$alias}"
   line="${line//'<user>'/$user}"
   line="${line//'<group>'/$group}"
   result="$result""$line"'\n'
done < $tmp
echo -e $result > $tmp
#if nullglob was set then, re-enable it
if [[ is_nullglob ]]; then
   shopt -s nullglob
fi
#move user's virtual domain to Apache 2 domain directory
......

3) Wie man sehen kann, wenn nullglob gesetzt ist, verhält es sich seltsam, wenn es einen String gibt, der ein * wie in enthält

<VirtualHost *:80>
 ServerName www.example.com

was wird

<VirtualHost ServerName www.example.com

es gibt keine Endwinkel und Apache2 kann nicht einmal geladen werden!

4) Diese Art des Parsens sollte langsamer als das Suchen und Ersetzen mit einem Treffer sein, aber wie Sie bereits gesehen haben, gibt es 4 Variablen für 4 verschiedene Suchmuster, die in einem einzigen Analysezyklus arbeiten!

Die am besten geeignete Lösung kann ich mir mit den gegebenen Annahmen des Problems vorstellen.

32
centurian

Sie können sed verwenden

sed -i 's/abc/XYZ/gi' /tmp/file.txt

Verwenden Sie -i für Groß-/Kleinschreibung ignorieren, wenn Sie nicht sicher sind, ob der zu suchende Text abc oder ABC oder AbC ist usw.

Sie können find und sed verwenden, wenn Sie Ihren Dateinamen jetzt nicht kennen:

 find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;

Suchen und Ersetzen in allen python Dateien:

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
20
MMParvin

Sie können auch den Befehl ed verwenden, um in Dateien zu suchen und zu ersetzen:

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 

Weitere Informationen finden Sie auf Website für Bash-Hacker

11
chrio

Seien Sie vorsichtig, wenn Sie URLs durch "/" ersetzen.

Ein Beispiel, wie es geht:

sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"

Auszug aus: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html

9
Linux4you

Wenn die Datei, an der Sie arbeiten, nicht so groß ist und die temporäre Speicherung in einer Variablen kein Problem darstellt, können Sie die Bash-Zeichenfolgensubstitution für die gesamte Datei gleichzeitig verwenden. Sie müssen sie nicht Zeile für Zeile durchgehen:

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt

Der gesamte Dateiinhalt wird als eine lange Zeichenfolge behandelt, einschließlich Zeilenumbrüchen.

XYZ kann eine Variable sein, z. B. $replacement, und ein Vorteil der Nichtverwendung von sed besteht darin, dass Sie nicht befürchten müssen, dass die Such- oder Ersetzungszeichenfolge möglicherweise das Trennzeichen sed pattern enthält (normalerweise, aber nicht unbedingt, /). Ein Nachteil ist, dass Sie keine regulären Ausdrücke oder komplexeren Operationen von sed verwenden können.

8
johnraff

Versuchen Sie den folgenden Shell-Befehl:

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
5
J Ajay

Um Text in der Datei nicht interaktiv zu bearbeiten, benötigen Sie einen Texteditor wie vim.

Hier ist ein einfaches Beispiel für die Verwendung über die Befehlszeile:

vim -esnc '%s/foo/bar/g|:wq' file.txt

Dies entspricht @ slim answer von ex editor, was im Grunde dasselbe ist.

Hier sind einige ex praktische Beispiele.

Ersetzen von Text foo durch bar in der Datei:

ex -s +%s/foo/bar/ge -cwq file.txt

Abschließende Leerzeichen für mehrere Dateien entfernen:

ex +'bufdo!%s/\s\+$//e' -cxa *.txt

Fehlerbehebung (wenn das Terminal feststeckt):

  • Fügen Sie -V1 param hinzu, um ausführliche Nachrichten anzuzeigen.
  • Beenden erzwingen durch: -cwq!.

Siehe auch:

4
kenorb

Sie können python auch innerhalb des Bash-Skripts verwenden. Ich hatte mit einigen der besten Antworten hier nicht viel Erfolg und fand, dass dies ohne die Notwendigkeit von Schleifen funktioniert:

#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'

s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()
2
micalith

Sie können den Befehl rpl verwenden. Zum Beispiel möchten Sie den Domainnamen im gesamten PHP-Projekt ändern.

rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/  

Dies ist kein klarer Grund, aber es ist sehr schnell und nützlich. :)

1
zalex