Warnung bezüglich '>'
Unix-Anfänger, die gerade etwas über die E / A-Umleitung gelernt haben ( <
und >
), probieren oft Dinge wie
befehl … eingabedatei > die_gleiche_datei
oder
befehle … < file > the_same_file
oder fast gleichwertig
cat Datei | befehl ...> die_gleiche_datei
( grep
, sed
, cut
, sort
, Und spell
sind Beispiele für Befehle , die Menschen versucht sind , in Konstrukte wie diese zu verwenden.) Die Benutzer sind überrascht zu entdecken , dass diese Szenarien in der Datei führen immer leer.
Eine Nuance, die in der anderen Antwort nicht erwähnt zu sein scheint, lauert im ersten Satz des Redirection- Abschnitts von bash (1) :
Bevor ein Befehl ausgeführt wird, können seine Eingabe und Ausgabe unter
Verwendung einer speziellen Notation umgeleitet werden, die von der Shell interpretiert wird.
Die ersten fünf Wörter sollten fett, kursiv, unterstrichen, vergrößert, blinkend, rot gefärbt und mit einem Symbol gekennzeichnet sein, um die Tatsache hervorzuheben, dass die Shell die angeforderten Umleitungen ausführt,
bevor der Befehl ausgeführt wird . Und erinnere dich auch
Die Umleitung der Ausgabe bewirkt, dass die Datei zum Schreiben geöffnet wird. Wenn die Datei nicht existiert, wird sie erstellt. Wenn es existiert, wird es auf die Größe Null gekürzt.
Also, in diesem Beispiel:
sort roster > roster
Die Shell öffnet die roster
Datei zum Schreiben und schneidet sie ab (dh, sie verwirft ihren gesamten Inhalt), bevor das sort
Programm ausgeführt wird. Natürlich kann nichts unternommen werden, um die Daten wiederherzustellen.
Man könnte das naiv erwarten
tr "[:upper:]" "[:lower:]" < poem > poem
könnte besser sein. Da die Shell Umleitungen von links nach rechts verarbeitet, wird sie poem
zum Lesen geöffnet (für tr
die Standardeingabe), bevor sie zum Schreiben geöffnet wird (für die Standardausgabe). Aber es hilft nicht. Obwohl diese Abfolge von Vorgängen zwei Dateizugriffsnummern ergibt, verweisen beide auf dieselbe Datei. Wenn die Shell die Datei zum Lesen öffnet, ist der Inhalt immer noch vorhanden, aber sie werden immer noch blockiert, bevor das Programm ausgeführt wird.
Also, was tun?
Die Lösungen umfassen:
Überprüfen Sie, ob das von Ihnen ausgeführte Programm über eine eigene interne Funktion verfügt, mit der Sie angeben können, wohin die Ausgabe gehen soll. Dies wird oft durch ein -o
(oder --output=
) Token angezeigt . Speziell,
sort roster -o roster
entspricht in etwa
sort roster > roster
Im ersten Fall sort
öffnet das Programm die Ausgabedatei. Und es ist klug genug, die Ausgabedatei erst zu öffnen, nachdem sie alle Eingabedateien gelesen hat.
In ähnlicher Weise zumindest einige Versionen sed
haben eine -i
(edit i n setzen) Option , die verwendet werden kann , die Ausgabe zurück an die Eingabedatei (wieder zu schreiben , nachdem alle Eingaben gelesen wurden). Editoren wie ed
/ ex
, emacs
, pico
und vi
/ vim
erlauben dem Benutzer eine Textdatei zu bearbeiten und die bearbeiteten Text in der Originaldatei speichern. Beachten Sie, dass ed
(mindestens) nicht interaktiv verwendet werden kann.
vi
hat eine verwandte Funktion. Wenn Sie tippen , wird der Inhalt des Bearbeitungspuffers ausgegeben, die Ausgabe gelesen und in den Puffer eingefügt (wobei der ursprüngliche Inhalt ersetzt wird).:%!command
Entercommand
Einfach aber effektiv:
befehl … eingabedatei > temp_datei && mv temp_datei eingabedatei
Dies hat den Nachteil, dass input_file
ein Link (wahrscheinlich) durch eine separate Datei ersetzt wird. Außerdem gehört die neue Datei Ihnen mit Standardschutz. Dies birgt insbesondere das Risiko, dass die Datei letztendlich weltweit lesbar ist, selbst wenn das Original dies input_file
nicht wäre.
Variationen:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
das wird immer noch (potenziell) die temp_file
Welt lesbar verlassen. Noch besser:
cp input_file temp_file && command … temp_file > input_file && rm temp_file
Dadurch bleiben der Link-Status, der Eigentümer und der Modus (Schutz) der Datei erhalten, was möglicherweise das Doppelte der E / A-Kosten zur Folge hat. (Möglicherweise müssen Sie eine Option wie -a
oder -p
on verwenden cp
, um die Attribute beizubehalten.)
command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(Nur aus Gründen der Lesbarkeit in separate Zeilen unterteilt.) Dadurch wird der Modus der Datei (und, wenn Sie als Root angemeldet sind, als Eigentümer) beibehalten. separate Datei.
Dieser Blog
("In-Place" -Bearbeitung von Dateien) schlägt vor und erklärt
{rm eingabedatei && befehl ...> eingabedatei ; } < Eingabedatei
Dies setzt voraus, dass die command
Standardeingabe verarbeitet werden kann (aber fast alle Filter können). Der Blog selbst nennt dies einen riskanten Kludge und rät von seiner Verwendung ab. Dadurch wird auch eine neue, separate Datei erstellt (die mit nichts verknüpft ist), die Ihnen gehört und über Standardberechtigungen verfügt.
Das moreutils-Paket hat einen Befehl namens sponge
:
befehl … eingabedatei | sponge the_same_file
Weitere Informationen finden Sie in dieser Antwort .
Folgendes hat mich völlig überrascht:
syntaxerror says :
[ Die meisten dieser Lösungen] werden auf einem schreibgeschützten Dateisystem versagen, wo „read-only“ bedeutet , dass Sie $HOME
wird beschreibbar sein, sondern /tmp
werden nur gelesen werden (Standardeinstellung). Wenn Sie beispielsweise Ubuntu verwenden und die Wiederherstellungskonsole gestartet haben, ist dies normalerweise der Fall. Auch die hier-Dokument Betreiber <<<
werden dort auch nicht funktionieren, da es erfordert /tmp
werden Lese- / Schreibzugriff ,
weil es eine temporäre Datei in auch dort schreiben.
(vgl. diese Frage enthält eine strace
'd Ausgabe)
In diesem Fall kann Folgendes funktionieren:
Also, was war die Frage?
Dies war ein beliebtes Thema in U & L; es wird in den folgenden Fragen angesprochen:
… Und das zählt nicht Super User oder Ask Ubuntu. Ich habe viele Informationen aus den Antworten auf die obigen Fragen hier in diese Antwort aufgenommen, aber nicht alle. (Das heißt, für weitere Informationen lesen Sie die oben aufgeführten Fragen und deren Antworten.)
PS Ich habe keine Verbindung zu dem Blog, das ich oben zitiert habe.