it-swarm.com.de

Wie ersetze ich eine Zeichenfolge in der 5. Zeile mehrerer Textdateien?

Ich möchte die 5. Zeile mehrerer Textdateien (file1.txt, file2.txt, file3.txt, file4.txt) mit einem einzigen Terminalbefehl durch die Zeichenfolge "Good Morning" ersetzen.

Alle Textdateien befinden sich auf meinem ~/Desktop.

Hinweis: Mein Desktop besteht aus 6 TXT-Dateien. Ich möchte die Änderung nur auf die oben genannten 4 Textdateien anwenden.

22
Avinash Raj

Hier sind einige Ansätze. Ich verwende Klammererweiterung (file{1..4}.txt), was file1.txt file2.txt file3.txt file4.txt bedeutet

  1. Perl

    Perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt
    

    Erläuterung:

    • -i: Bewirkt, dass Perl die Dateien an Ort und Stelle bearbeitet und die Originaldatei ändert.

      Wenn nach -i ein Dateierweiterungssuffix folgt, wird für jede Datei, die geändert wird, eine Sicherungskopie erstellt. Beispiel: -i.bak erstellt einen file1.txt.bak, wenn file1.txt während der Ausführung geändert wird.

    • -p: Bedeutet, dass die Eingabedatei zeilenweise gelesen, das Skript angewendet und gedruckt wird.

    • -e: Ermöglicht die Übergabe eines Skripts über die Befehlszeile.

    • s/.*/ Good Morning /: Damit wird der Text in der aktuellen Zeile (.*) durch Good Morning ersetzt.

    • $. ist eine spezielle Perl-Variable, die die aktuelle Zeilennummer der Eingabedatei enthält. Also bedeutet s/foo/bar/ if $.==5, foo nur in der 5. Zeile durch bar zu ersetzen.

  2. sed

    sed -i '5s/.*/ Good Morning /' file{1..4}.txt
    

    Erläuterung:

    • -i: Bearbeiten Sie die Datei wie bei Perl.

    Standardmäßig druckt sed jede Zeile der Eingabedatei. Der 5s/pattern/replacement/ bedeutet Ersatzmuster mit Ersetzung in der 5. Zeile.

  3. Awk

    for f in file{1..4}.txt; do 
        awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f"; 
    done
    

    Erläuterung:

    awk hat keine Entsprechung zur Option -i¹. Dies bedeutet, dass eine temporäre Datei (foobar) erstellt werden muss, die dann umbenannt wird, um das Original zu überschreiben. Die Bash-Schleife for f in file{1..4}.txt; do ... ; done durchläuft einfach jeden von file{1..4}.txt und speichert den aktuellen Dateinamen als $f. In awk ist NR die aktuelle Zeilennummer und $0 der Inhalt der aktuellen Zeile. Daher ersetzt das Skript die Zeile ($0) nur in der 5. Zeile durch "Good Morning". 1; ist awk für "print the line".

    ¹Neuere Versionen tun, was der Entwickler in seinem Antwort gezeigt hat.

  4. coreutils

    for f in file{1..4}.txt; do 
        (head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar && 
        mv foobar "$f"; 
    done 
    

    Erläuterung:

    Die Schleife wird im vorherigen Abschnitt erläutert.

    • head -4: Die ersten 4 Zeilen werden gedruckt

    • echo " Good Morning ": print "Guten Morgen"

    • tail -n +6: druckt alles von der 6. Zeile bis zum Ende der Datei

    Die Klammern ( ) um diese drei Befehle ermöglichen es Ihnen, die Ausgabe aller drei (also der ersten vier Zeilen, dann "Guten Morgen", dann der Rest der Zeilen) zu erfassen und sie in eine Datei umzuleiten.

39
terdon

Sie könnten sed verwenden:

sed '5s/^/Good morning /' file

würde Good morning in der fünften Zeile einer Datei anhängen.

Wenn Sie stattdessen den Inhalt in Zeile 5 ersetzen möchten, sagen Sie:

sed '5s/.*/Good morning/' file

Wenn Sie die Änderungen an der Datei direkt speichern möchten, verwenden Sie die Option -i:

sed -i '5s/.*/Good morning/' file

sed kann mehrere Dateien gleichzeitig verarbeiten. Sie können am Ende des Befehls einfach weitere Dateinamen hinzufügen. Sie können auch Bash-Erweiterungen verwenden, um bestimmte Dateien abzugleichen:

# manually specified
sed -i '5s/.*/Good morning/' file1.txt file2.txt file3.txt file4.txt

# wildcard: all files on the desktop
sed -i '5s/.*/Good morning/' ~/Desktop/*

# brace expansion: file1.txt, file2.txt, file3.txt, file4.txt
sed -i '5s/.*/Good morning/' file{1..4}.txt

Sie können mehr über Klammererweiterungen hier lesen .


GNU awk-Versionen 4.1.0 und höher enthalten eine Erweiterung , die die direkte Bearbeitung ermöglichen. Man könnte also sagen:

gawk -i inplace 'NR==5{$0="Good morning"}7' file

zeile 5 in der Datei durch Good morning ersetzen!

23
devnull

Ich habe keine python Lösung gesehen, also hier ist es:

import sys
import os
def open_and_replace(filename):

    with open(filename) as read_file:
        temp = open("/tmp/temp.txt","w")
        for index,line in enumerate(read_file,1):
            if  index == 5:
                temp.write("NEW STRING\n")
            else:
                temp.write(line.strip() + "\n")
        temp.close()
    os.rename("/tmp/temp.txt",filename)

for file_name in sys.argv[1:]:
    open_and_replace(file_name)

Die Grundidee ist, dass für jede Datei, die in der Befehlszeile als Argument angegeben wird, eine temporäre Datei geschrieben und jede Zeile in der Originaldatei aufgelistet wird. Wenn der Index der Zeile 5 ist, schreiben wir eine andere Zeile aus. Der Rest ersetzt nur die alte Datei durch die temporäre Datei Demo:

$> ls
file1.txt  file2.txt  file3.txt
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
GOOD MORNING
line 6
$> python ~/replace_5th_line.py file1.txt file2.txt  file3.txt                 
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6
$> cat file2.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6

Dasselbe kann mit Listenverständnis erreicht werden. Unten ist ein Einzeiler des gleichen Skripts:

cat /etc/passwd | python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])'

oder ohne cat

python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])' < /etc/passwd

Was bleibt, ist einfach die Ausgabe von bearbeiteten Inhalten in eine andere Datei mit > output.txt umzuleiten.

2

Sie können Vim im Ex-Modus verwenden:

for b in 1 2 3 4
do
  ex -sc '5c|Good Morning' -cx file"$b".txt
done
  1. 5 5. Zeile auswählen

  2. c Ersetzen Sie den Text

  3. x schreiben, wenn Änderungen vorgenommen wurden (sie haben) und beenden

1
Steven Penny

Das Folgende ist ein Bash-Skript, das abschließt der in dieser Antwort vorgeschlagene Perl-Prozess

Beispiel:

/tmp/it

console:
  enabled:false

Führen Sie dann Folgendes aus:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

und die Datei enthält jetzt

/tmp/it

console:
  enabled:true

search_and_replace_on_line_of_file.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH REPLACE LINE_NUM FILE

  e.g. 

  false true 52 /tmp/it  -> replaces false with true on line 52 of file /tmp/it

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$4" ]
then
  show_help
fi

SEARCH_FOR=$1
REPLACE_WITH=$2
LINE_NO=$3
FILE_NAME=$4
Perl -i -pe "s/$SEARCH_FOR/$REPLACE_WITH/ if $.==$LINE_NO" $FILE_NAME 
0
brad parks