Wie führe ich einen Befehl Bearbeiten der Datei (Argument) „in place“ bash verwenden?

StackOverflow https://stackoverflow.com/questions/146435

  •  02-07-2019
  •  | 
  •  

Frage

Ich habe eine Datei temp.txt, dass ich mit dem sort Befehl in bash sortieren möchten.

Ich möchte die sortierten Ergebnisse die Originaldatei ersetzen.

Das funktioniert nicht, zum Beispiel (ich eine leere Datei erhalten):

sortx temp.txt > temp.txt

Kann man das in einer Zeile durchgeführt werden, ohne das Kopieren zu temporären Dateien zurückgreifen?


EDIT: Die -o Option ist sehr cool für sort. Früher habe ich sort in meiner Frage als Beispiel. Ich laufe in das gleiche Problem mit anderen Befehlen:

uniq temp.txt > temp.txt.

Gibt es eine bessere allgemeine Lösung?

War es hilfreich?

Lösung

sort temp.txt -o temp.txt

Andere Tipps

Ein sort muss alle Eingaben sehen, bevor es zur Ausgabe beginnen. Aus diesem Grunde kann das sort Programm leicht eine Option bietet eine Datei an Ort und Stelle zu ändern:

sort temp.txt -o temp.txt

Insbesondere die Dokumentation von GNU sort sagt :

  

Normalerweise liest sortieren alle Eingaben vor der Ausgabe-Datei zu öffnen, so dass Sie sicher eine Datei anstelle sortieren, indem Befehle wie sort -o F F und cat F | sort -o F verwenden. Allerdings sort mit --merge (-m) kann die Ausgabedatei öffnen, bevor alle Eingaben zu lesen, so dass ein Befehl wie cat F | sort -m -o F - G ist nicht sicher, als eine Art beginnen könnte F schreiben vor cat getan wird es zu lesen.

Während die Dokumentation von BSD sort sagt:

  

Wenn [die] Ausgabedatei eine der Input-Dateien ist, sortieren kopiert sie in eine temporäre Datei vor dem Sortieren und Schreiben der Ausgabe an [die] Ausgabedatei.

Befehle wie uniq können schriftlich Ausgabe beginnen, bevor sie die Eingabe zu beenden, zu lesen. Diese Befehle normalerweise nicht unterstützen, in-Place-Bearbeitung (und es wäre schwieriger für sie, um diese Funktion zu unterstützen).

Sie arbeiten in der Regel um diesen mit einer temporären Datei, oder wenn Sie unbedingt eine Zwischendatei, um zu vermeiden mögen, können Sie einen Puffer verwenden, um das vollständige Ergebnis zu speichern, bevor es heraus zu schreiben. Zum Beispiel mit perl:

uniq temp.txt | perl -e 'undef $/; $_ = <>; open(OUT,">temp.txt"); print OUT;'

Hier liest der Perl-Teil die komplette Ausgabe von uniq in variablen $_ und dann überschreibt die ursprüngliche Datei mit diesen Daten. Sie könnten das gleiche in der Skriptsprache Ihrer Wahl tun, vielleicht sogar in Bash. Aber beachten Sie, dass es genügend Speicher benötigt, um die gesamte Datei zu speichern, ist dies nicht ratsam ist, wenn sie mit großen Dateien arbeiten.

Hier ist ein allgemeiner Ansatz, arbeitet mit uniq, sortieren und so weiter.

{ rm file && uniq > file; } < file

Tobu Kommentar auf Schwamm garantiert eine Antwort in seinem eigenen Recht zu sein.

Ein Zitat aus der moreutils Homepage:

  

Die wohl universelles Werkzeug in moreutils so weit ist Schwamm (1), die Sie Dinge wie diese tun können:

% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd

Allerdings leidet sponge unter dem gleichen Problem Steve Jessop hier kommentiert. Wenn einer der Befehle in der Pipeline vor sponge scheitert, dann wird die ursprüngliche Datei überschrieben werden.

$ mistyped_command my-important-file | sponge my-important-file
mistyped-command: command not found

Uh-oh, my-important-file ist weg.

Hier gehen Sie, eine Zeile:

sort temp.txt > temp.txt.sort && mv temp.txt.sort temp.txt

Technisch gibt es keine Kopie in eine temporäre Datei und der Befehl sollte sofort sein ‚mv‘.

Ich mag die sort file -o file Antwort will aber nicht die gleichen Dateinamen zweimal eingeben.

Mit BASH Geschichte Expansion :

$ sort file -o !#^

packt die erste ARG aktuelle Zeile, wenn Sie die Taste eingeben .

Eine einzigartige Art an Ort und Stelle:

$ sort -u -o file !#$

greift nach der letzten arg in der aktuellen Zeile.

Viele haben die erwähnt -o Option. Hier ist der Manpage Teil.

Aus der Manpage:

   -o output-file
          Write output to output-file instead of to the  standard  output.
          If  output-file  is  one of the input files, sort copies it to a
          temporary file before sorting and writing the output to  output-
          file.

Dies würde sehr wenig Speicher, aber man kann awk verwenden, um die Zwischendaten im Speicher zu speichern, und dann schreibst wieder aus.

uniq temp.txt | awk '{line[i++] = $0}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt

Eine Alternative mit dem häufigeren sponge sed:

sed -ni r<(command file) file

Es funktioniert für jeden Befehl (sort, uniq, tac, ...) und verwendet die sehr gut bekannt sed der -i Option (bearbeiten von Dateien in-place).

. Achtung: Versuchen command file zuerst, weil die Bearbeitung von Dateien an Ort und Stelle von Natur aus nicht sicher ist,


Erklärung

Zuerst Sie sagen sed nicht die (original) Linien zu drucken ( -n Option ) und mit Hilfe der sed href="http://www.grymoire.com/Unix/Sed.html#uh-37" rel="nofollow"> r Befehl und Prozess Substitution des bash, der erzeugte Inhalt durch <(command file) wird der Ausgang gespeichert wird anstelle .


Die Dinge noch einfacher

Sie können diese Lösung in eine Funktion wickeln:

ip_cmd() { # in place command
    CMD=${1:?You must specify a command}
    FILE=${2:?You must specify a file}
    sed -ni r<("$CMD" "$FILE") "$FILE"
}

Beispiel

$ cat file
d
b
c
b
a

$ ip_cmd sort file
$ cat file
a
b
b
c
d

$ ip_cmd uniq file
$ cat file
a
b
c
d

$ ip_cmd tac file
$ cat file
d
c
b
a

$ ip_cmd
bash: 1: You must specify a command
$ ip_cmd uniq
bash: 2: You must specify a file

Mit dem Argument --output= oder -o

Gerade versucht unter FreeBSD:

sort temp.txt -otemp.txt

die uniq Fähigkeit hinzuzufügen, was sind die Nachteile auf:

sort inputfile | uniq | sort -o inputfile

Lesen Sie oben auf dem nicht-interaktiven Editor, ex .

Wenn Sie darauf bestehen, das sort Programm auf verwenden, müssen Sie eine Zwischendatei verwenden - ich glaube nicht, sort hat eine Option für im Speicher zu sortieren. Jeder anderer Trick mit stdin / stdout wird fehlschlagen, wenn Sie garantieren können, dass die Puffergröße für die Art des stdin groß genug ist, um die gesamte Datei zu passen.

Edit: Schande über mich. sort temp.txt -o temp.txt funktioniert ausgezeichnet.

Eine andere Lösung:

uniq file 1<> file
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top