it-swarm.com.de

So ersetzen Sie eine ganze Zeile in einer Textdatei durch die Zeilennummer

Ich möchte, dass ein Bash-Skript eine ganze Zeile in einer Datei ersetzt. Die Zeilennummer ist immer gleich, so dass es sich um eine fest codierte Variable handeln kann.

Ich versuche nicht, eine Teilzeichenfolge in dieser Zeile zu ersetzen, sondern möchte diese Zeile nur vollständig durch eine neue Zeile ersetzen.

Gibt es Bash-Methoden dafür (oder etwas Einfaches, das in ein .sh-Skript geworfen werden kann)?.

136
user788171

Nicht die größte, aber das sollte funktionieren:

sed -i 'Ns/.*/replacement-line/' file.txt

dabei sollte N durch Ihre Zielzeilennummer ersetzt werden. Dies ersetzt die Zeile in der Originaldatei. Um den geänderten Text in einer anderen Datei zu speichern, lassen Sie das -i Möglichkeit:

sed 'Ns/.*/replacement-line/' file.txt > new_file.txt
196
chepner

Ich habe dieses Skript tatsächlich verwendet, um eine Codezeile in der Cron-Datei auf den UNIX-Servern unseres Unternehmens vor einiger Zeit zu ersetzen. Wir haben es als normales Shell-Skript ausgeführt und hatten keine Probleme:

#Create temporary file with new line in place
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
#Copy the new file over the original file
mv /dir/temp_file /dir/file

Dies erfolgt nicht nach Zeilennummer, Sie können jedoch problemlos zu einem zeilennummernbasierten System wechseln, indem Sie die Zeilennummer vor s/ Und einen Platzhalter anstelle von the_original_line Einfügen.

42
Kyle

Angenommen, Sie möchten Zeile 4 durch den Text "different" ersetzen. Sie können AWK wie folgt verwenden:

awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt

AWK betrachtet die Eingabe als "Datensätze", die in "Felder" unterteilt sind. Standardmäßig ist eine Zeile ein Datensatz. NR ist die Anzahl der angezeigten Datensätze. $0 Stellt den aktuellen vollständigen Datensatz dar (während $1 Das erste Feld des Datensatzes ist und so weiter; standardmäßig sind die Felder Wörter aus der Zeile).

Wenn also die aktuelle Zeilennummer 4 ist, drucken Sie die Zeichenfolge "anders", ansonsten drucken Sie die Zeile unverändert.

In AWK wird der in { } Enthaltene Programmcode für jeden Eingabesatz einmal ausgeführt.

Sie müssen das AWK-Programm in einfachen Anführungszeichen setzen, damit die Shell nicht versucht, Dinge wie $0 Zu interpretieren.

EDIT: Ein kürzeres und eleganteres AWK-Programm von @chepner in den Kommentaren unten:

awk 'NR==4 {$0="different"} { print }' input_file.txt

Ersetzen Sie nur für Datensatz (d. H. Zeile) Nummer 4 den gesamten Datensatz durch die Zeichenfolge "anders". Drucken Sie dann für jeden Eingabedatensatz den Datensatz aus.

Offensichtlich sind meine AWK-Fähigkeiten rostig! Vielen Dank, @chepner.

EDIT: und siehe auch eine noch kürzere Version von @Dennis Williamson:

awk 'NR==4 {$0="different"} 1' input_file.txt

Wie das geht, lesen Sie in den Kommentaren: Das 1 Wertet immer true aus, so dass der zugehörige Codeblock immer ausgeführt wird. Es ist jedoch kein Codeblock zugeordnet, was bedeutet, dass AWK standardmäßig nur die gesamte Zeile druckt. AWK wurde entwickelt, um knappe Programme wie dieses zu ermöglichen.

19
steveha

Angesichts dieser Testdatei (test.txt)

Lorem ipsum dolor sit amet,
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

der folgende Befehl ersetzt die erste Zeile in "Newline Text"

$ sed '1 c\
> newline text' test.txt

Ergebnis:

newline text
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

weitere Informationen finden Sie hier

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/

14
Eric Robinson

ersetzen Sie in bash N, M durch die Zeilennummern und xxx yyy durch das, was Sie möchten

i=1
while read line;do
  if((i==N));then
    echo 'xxx'
  Elif((i==M));then
    echo 'yyy'
  else
    echo "$line"
  fi
  ((i++))
done  < orig-file > new-file

BEARBEITEN

Tatsächlich gibt es bei dieser Lösung einige Probleme mit den Zeichen "\ 0" "\ t" und "\".

"\ t" kann durch Setzen von IFS = vor "\" am Ende der Zeile mit -r gelöst werden

IFS= read -r line

aber für "\ 0" ist die Variable abgeschnitten, es gibt keine Lösung in reiner Bash: Ordne einer Variablen in Bash einen String zu, der ein Nullzeichen (\ 0) enthält Aber in einer normalen Textdatei gibt es das Kein Nullzeichen\0

Perl wäre eine bessere Wahl

Perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file
7
# Replace the line of the given line number with the given replacement in the given file.
function replace-line-in-file() {
    local file="$1"
    local line_num="$2"
    local replacement="$3"

    # Escape backslash, forward slash and ampersand for use as a sed replacement.
    replacement_escaped=$( echo "$replacement" | sed -e 's/[\/&]/\\&/g' )

    sed -i "${line_num}s/.*/$replacement_escaped/" "$file"
}
3
Daniel Bigham

Hervorragende Antwort von Chepner. Es funktioniert für mich in Bash Shell.

 # To update/replace the new line string value with the exiting line of the file
 MyFile=/tmp/ps_checkdb.flag

 `sed -i "${index}s/.*/${newLine}/" $MyFile`

hier
index - Zeilennr
newLine - neuer Zeilenstring, den wir ersetzen wollen.


In ähnlicher Weise wird der folgende Code zum Lesen einer bestimmten Zeile in der Datei verwendet. Dies hat keine Auswirkungen auf die eigentliche Datei.

LineString=`sed "$index!d" $MyFile` 

hier
!d - löscht die Zeilen mit Ausnahme von Zeile Nr. $index, Sodass die Ausgabe als Zeilenfolge ohne $index In der Datei erfolgt.

2

Auf dem Mac habe ich verwendet

sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name
1
nakeer