it-swarm.com.de

So ersetzen Sie einen String in mehreren Dateien in der Linux-Befehlszeile

Ich muss eine Zeichenfolge in vielen Dateien in einem Ordner ersetzen, wobei nur ssh Zugriff auf den Server besteht. Wie kann ich das machen?

317
mridul4c
cd /path/to/your/folder
sed -i 's/foo/bar/g' *

Vorkommen von "foo" werden durch "bar" ersetzt.

448
kev

Ähnlich wie Kaspars Antwort, jedoch mit der Markierung g, um alle Vorkommnisse in einer Zeile zu ersetzen. 

find ./ -type f -exec sed -i 's/string1/string2/g' {} \;

Bei globaler Groß- und Kleinschreibung:

find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
184

@ kevs Antwort ist gut, betrifft jedoch nur Dateien im unmittelbaren Verzeichnis. Das folgende Beispiel verwendet grep, um Dateien rekursiv zu finden. Es funktioniert jedes Mal für mich.

grep -rli 'old-Word' * | xargs [email protected] sed -i 's/old-Word/new-Word/g' @
110
pymarco

Das hat für mich funktioniert:

find ./ -type f -exec sed -i 's/string1/string2/' {} \;

Dies tat jedoch nicht: sed -i 's/string1/string2/g' *. Vielleicht sollte "foo" nicht string1 und "bar" sein, nicht string2.

25
Kaspar L. Palgi

Um eine Zeichenfolge in mehreren Dateien zu ersetzen, können Sie Folgendes verwenden:

grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'

Z.B.

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

Quellblog

23
Djacomo

Hierfür gibt es einige Standardantworten. Im Allgemeinen können Sie find verwenden, um die Dateien rekursiv aufzulisten und anschließend die Operationen mit sed oder Perl auszuführen.

Bei den meisten schnellen Anwendungen ist der Befehl rpl viel einfacher zu merken. Hier ist der Ersatz (foo -> bar), rekursiv für alle Dateien:

rpl -R foo bar .

Sie müssen es wahrscheinlich installieren (apt-get install rpl oder ähnlich).

Bei härteren Jobs, die reguläre Ausdrücke und Rückersetzung beinhalten, oder das Umbenennen von Dateien sowie Suchen und Ersetzen, ist das allgemeinste und leistungsfähigste Werkzeug, das mir bekannt ist, repren , a kleines Python-Skript Ich habe vor einiger Zeit für ein paar umständliche Umbenennungs- und Umgestaltungsaufgaben geschrieben. Die Gründe, die Sie bevorzugen könnten, sind:

  • Unterstützt das Umbenennen von Dateien sowie Suchen und Ersetzen von Dateiinhalten.
  • Sehen Sie sich die Änderungen an, bevor Sie die Suche und das Ersetzen durchführen.
  • Unterstützen Sie reguläre Ausdrücke mit Rücksetzungsfunktion, ganzen Wörtern, Groß- und Kleinschreibung, Groß- und Kleinschreibung (Ersetzung von foo -> bar, Foo -> Bar, FOO -> BAR).
  • Funktioniert mit mehreren Ersetzungen, einschließlich Swaps (foo -> bar und bar -> foo) oder nicht eindeutigen Ersetzungen (foo -> bar, f -> x).

Um es zu benutzen, pip install repren. Überprüfen Sie die Beispiele unter README .

23
jlevy

Um einen Pfad in Dateien zu ersetzen (Escape-Zeichen zu vermeiden), können Sie den folgenden Befehl verwenden:

sed -i '[email protected][email protected][email protected]'

Das @ -Zeichen bedeutet, dass alle Sonderzeichen in einer folgenden Zeichenfolge ignoriert werden sollen.

17

Falls Ihre Zeichenfolge einen Schrägstrich (/) enthält, können Sie das Trennzeichen in '+' ändern.

find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +

Dieser Befehl würde im aktuellen Verzeichnis rekursiv ausgeführt.

11
gopiariv

Die ersten Vorkommen von "foo" werden durch "bar" ersetzt. Und Sie können die zweite Zeile verwenden, um zu überprüfen.

grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
10
jiasir

Wenn Sie eine Liste von Dateien haben, können Sie diese verwenden 

replace "old_string" "new_string" -- file_name1 file_name2 file_name3

Wenn Sie alle Dateien haben, die Sie verwenden können 

replace "old_string" "new_string" -- *

Wenn Sie eine Liste mit Dateien mit der Erweiterung haben, können Sie verwenden 

replace "old_string" "new_string" -- *.extension
8
Pawel Dubiel

Ich habe meine eigene Lösung zusammengestellt, bevor ich diese Frage (und Antworten) gefunden habe ... Ich habe nach verschiedenen Kombinationen von "replace", "mehrere" und "xml" gesucht, weil dies meine Anwendung war, aber diese bestimmte nicht gefunden hat.

Mein Problem: Ich hatte Quell-XML-Dateien mit Daten für Testfälle, die komplexe Objekte enthielten. Ein Refactor im Java-Quellcode hat viele Klassen geändert und nicht auf die XML-Datendateien angewendet. Um die Testfalldaten zu speichern, musste ich alle Klassennamen in allen XML-Dateien ändern, die auf mehrere Verzeichnisse verteilt waren. Alle beim Speichern von Sicherungskopien der ursprünglichen XML-Dateien (obwohl dies kein Muss war, da die Versionskontrolle mich hier retten würde).

Ich habe nach einer Kombination von find + sed gesucht, weil es in anderen Situationen für mich funktioniert hat, aber nicht mit mehreren Ersetzungen gleichzeitig.

Dann fand ich ask ubuntu response und es half mir dabei, meine Kommandozeile aufzubauen:

find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

Und es hat perfekt funktioniert (naja, in meinem Fall gab es sechs verschiedene Ersetzungen). Beachten Sie jedoch, dass alle * .xml-Dateien im aktuellen Verzeichnis berührt werden. Aus diesem Grund und wenn Sie gegenüber einem Versionskontrollsystem verantwortlich sind, möchten Sie möglicherweise zuerst filtern und nur an sed übergeben, die tatsächlich die gewünschten Zeichenfolgen haben. mögen:

find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
4
manuelvigarcia

"Sie könnten auch find und sed verwenden, aber ich finde, dass diese kleine Perllinie gut funktioniert.

Perl -pi -w -e 's/search/replace/g;' *.php
  • -e bedeutet, dass die folgende Codezeile ausgeführt wird.
  • -i bedeutet Bearbeiten vor Ort
  • -w schreibt Warnungen
  • -p Schleife

"(Extrahiert aus http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php )

Meine besten Ergebnisse werden mit Perl und Grep erzielt (um sicherzustellen, dass die Datei über den Suchausdruck verfügt).

Perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
grep --include={*.php,*.html} -rnl './' -e "old" | xargs [email protected] sed -i 's/old/new/g' @
3
Dennis

Skript für Multiedit-Befehl

multiedit [-n PATTERN] OLDSTRING NEWSTRING

Von Kaspar's Antwort aus habe ich ein Bash-Skript erstellt, um Befehlszeilenargumente zu akzeptieren und optional die Dateinamen auf ein Muster zu beschränken. Speichern Sie in Ihrem $ PATH und machen Sie die ausführbare Datei, dann verwenden Sie einfach den obigen Befehl.

Hier ist das Skript:

#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n

[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"

# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then  # if -n option is given:
        # replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
        find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
        # replace OLDSTRING with NEWSTRING recursively in all files
        find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi
2

Wirklich lahm, aber ich konnte keinen sed-Befehl bekommen, um direkt unter OSX zu funktionieren, also habe ich stattdessen dieses dumme Ding gemacht:

:%s/foo/bar/g
:wn

^ - kopiere diese drei Zeilen in meine Zwischenablage (ja, füge die Endzeile ein) und dann:

vi *

und halten Sie Befehlstaste-v gedrückt, bis keine Dateien mehr vorhanden sind.

Dumm ... hackig ... effektiv ...

2
Justin

Um meinen persönlichen englischen Knoten beizubehalten, habe ich ein Hilfsskript geschrieben, mit dem mehrere alte/neue Zeichenfolgen für alle Dateien in einem Verzeichnis rekursiv ersetzt werden können.

Das alte/neue String-Paar wird in einer Hash-Map verwaltet.

Das Verzeichnis kann über die Befehlszeile oder die Umgebungsvariable festgelegt werden. Die Karte ist im Skript hartcodiert. Sie können den Code jedoch ändern, um ihn aus einer Datei zu laden.

Aufgrund einiger Neuerungen ist Bash 4.2 erforderlich.

de_standardize.sh:

#! /bin/bash
# (need bash 4.2+,)
# 
# Standardize phonetic symbol of English.
# 
# format:
#   en_standardize.sh [<dir>]
# 
# params:
# * dir
#   target dir, optional,
#   if not specified then use environment variable "$node_dir_en",
#   if both not provided, then will not execute,
# * 
# 

paramCount=$#

# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
    echo -e "dir specified (in command):\n\t$1\n"
    targetDir=$1
Elif [[ -v node_dir_en ]]; then # environable set,
    echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
    targetDir=$node_dir_en
else # environable not set,
    echo "dir not specified, won't execute"
    exit
fi

# check whether dir exists,
if [ -d $targetDir ]; then
    cd $targetDir
else
    echo -e "invalid dir location:\n\t$targetDir\n"
    exit
fi

# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")

# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
    echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'

# do replace,
for key in "${!itemMap[@]}"; do
    grep -rli "$key" * | xargs [email protected] sed -i "s/$key/${itemMap[$key]}/g" @
done

echo -e "\nDone."
exit
1
Eric Wang

Der Stream-Editor ändert mehrere Dateien "inplace", wenn er mit dem -i-Schalter aufgerufen wird, der eine Sicherungsdatei benötigt, die als Argument endet. So

sed -i.bak 's/foo/bar/g' *

ersetzt foo durch bar in allen Dateien in diesem Ordner, wird jedoch nicht in Unterordner abgelegt. Dadurch wird jedoch für jede Datei in Ihrem Verzeichnis eine neue .bak-Datei erstellt. Um dies rekursiv für alle Dateien in diesem Verzeichnis und allen seinen Unterverzeichnissen durchzuführen, benötigen Sie einen Helfer wie find, um die Verzeichnisstruktur zu durchlaufen.

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

Mit find können Sie weitere Einschränkungen für die zu ändernden Dateien festlegen, indem Sie ggf. weitere Argumente wie find ./ -name '*.php' -or -name '*.html' -print0 angeben.


Hinweis: GNU sed erfordert keine Dateiendung, sed -i 's/foo/bar/g' * funktioniert auch; FreeBSD sed erfordert eine Erweiterung, lässt jedoch einen Platz dazwischen frei, so dass sed -i .bak s/foo/bar/g * funktioniert.

1
Anaphory

Wenn die Datei Backslashes (Pfade normalerweise) enthält, können Sie Folgendes versuchen:

sed -i -- 's,<path1>,<path2>,g' *

ex:

sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all Shell scripts available)
1
Shaik Amanulla

Ich fand dieses von einem anderen Beitrag (kann mich nicht erinnern, welche) und obwohl nicht das eleganteste, es ist einfach und als Neuling Linux-Benutzer hat mir keine Mühe gegeben

for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done

wenn Sie Leerzeichen oder andere Sonderzeichen haben, verwenden Sie ein \ 

for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done

für Zeichenfolgen in Unterverzeichnissen verwenden **

for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
0
Kyle Turck

Ich gebe ein Beispiel für die Behebung eines häufigen Shebang-Fehlers in Python-Quellen.

Sie können den grep/sed-Ansatz ausprobieren. Hier ist eine, die mit GNU sed funktioniert und kein Git-Repo brechen wird:

$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}

Oder Sie können greptile :) verwenden 

$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .

Ich habe gerade das erste Skript getestet und das zweite sollte auch funktionieren. Seien Sie vorsichtig mit Escape-Zeichen. Ich denke, es sollte in den meisten Fällen einfacher sein, Greptile zu verwenden. Natürlich können Sie mit sed viele interessante Dinge tun, und deshalb ist es besser, wenn Sie es mit xargs beherrschen.

0
exa

Auf einem MacBook Pro habe ich Folgendes verwendet (inspiriert von https://stackoverflow.com/a/19457213/6169225 ):

sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *

-i '' stellt sicher, dass Sie keine Backups erstellen.

-e für moderne Regex.

0
Marquistador

Der Befehl unten kann verwendet werden, um zuerst die Dateien zu durchsuchen und die Dateien zu ersetzen

finden . xargs grep Suchstring | sed 's/Suchstring/neuer String/g'

z.B. finden. | xargs grep abc | sed 's/abc/xyz/g'

0
Amit

Es gibt eine einfachere Möglichkeit, eine einfache Skriptdatei zu verwenden:

   # Sudo chmod +x /bin/replace_string_files_present_dir

öffne die Datei in gedit oder einem Editor deiner Wahl, ich benutze hier gedit.

   # Sudo gedit /bin/replace_string_files_present_dir

Fügen Sie dann im Editor Folgendes in die Datei ein

   #!/bin/bash
   replace "oldstring" "newstring" -- *
   replace "oldstring1" "newstring2" -- *
   #add as many lines of replace as there are your strings to be replaced for 
   #example here i have two sets of strings to replace which are oldstring and 
   #oldstring1 so I use two replace lines.

Speichern Sie die Datei, schließen Sie gedit, beenden Sie Ihr Terminal oder schließen Sie es einfach und starten Sie es, um das neu hinzugefügte Skript zu laden.

Navigieren Sie zu dem Verzeichnis, in dem Sie mehrere Dateien haben, die Sie bearbeiten möchten. Dann renne:

  #replace_string_files_present_dir

Drücken Sie die Eingabetaste und dies ersetzt automatisch die oldstring und oldstring1 in allen Dateien, die sie enthalten, mit den richtigen newstring und newstring1 jeweils.

Es werden alle Verzeichnisse und Dateien übersprungen, die die alten Zeichenfolgen nicht enthalten.

Dies kann dazu beitragen, die mühsame Arbeit des Tippens zu vermeiden, wenn Sie mehrere Verzeichnisse mit Dateien haben, die ersetzt werden müssen. Alles was Sie tun müssen, ist zu jedem dieser Verzeichnisse zu navigieren und dann auszuführen:

#replace_string_files_present_dir

Alles, was Sie tun müssen, ist sicherzustellen, dass Sie alle Ersatzzeichenfolgen, wie oben gezeigt, eingefügt oder hinzugefügt haben:

replace "oldstring" "newstring" -- *

am Ende der Datei / bin/replace_string_files_present_dir.

Um eine neue Ersetzungszeichenfolge hinzuzufügen, öffnen Sie einfach das von uns erstellte Skript, indem Sie Folgendes in das Terminal eingeben:

Sudo gedit /bin/replace_string_files_present_dir

Kümmern Sie sich nicht um die Anzahl der Ersetzungszeichenfolgen, die Sie hinzufügen. Sie haben keine Auswirkung, wenn die alte Zeichenfolge nicht gefunden wird.

0
briancollins081

Die Verwendung des Befehls ack wäre viel schneller:

ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'

Auch wenn Sie ein Leerzeichen im Suchergebnis haben. Du musst dem entkommen. 

0

Angenommen, Sie möchten nach der Zeichenfolge search suchen und diese in mehreren Dateien durch replace ersetzen. Dies ist meine kampferprobte einzeilige Formel :

grep -RiIl 'search' | xargs sed -i 's/search/replace/g'

Schnelle grep Erklärung:

  • -R - rekursive Suche
  • -i - Groß- und Kleinschreibung wird nicht berücksichtigt
  • -I - überspringe Binärdateien (du willst Text, oder?)
  • -l - druckt eine einfache Liste als Ausgabe. Wird für die anderen Befehle benötigt

Die grep-Ausgabe wird dann an sed (über xargs) weitergeleitet, um tatsächlich Text zu ersetzen. Das -i -Flag ändert die Datei direkt. Entfernen Sie es für eine Art "Trockenlauf" -Modus.

0
Ignorant