Wie führe ich einen Befehl Bearbeiten der Datei (Argument) „in place“ bash verwenden?
-
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?
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
undcat F | sort -o F
verwenden. Allerdingssort
mit--merge
(-m
) kann die Ausgabedatei öffnen, bevor alle Eingaben zu lesen, so dass ein Befehl wiecat F | sort -m -o F - G
ist nicht sicher, als eine Art beginnen könnteF
schreiben vorcat
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