Dies ist wahrscheinlich eine komplexe Lösung .
Ich suche einen einfachen Operator wie ">>", aber zum Voranstellen.
Ich fürchte, es existiert nicht. Ich muss so etwas tun
mv myfile tmp cat myheader tmp> myfile
Etwas schlauer?
Dies ist wahrscheinlich eine komplexe Lösung .
Ich suche einen einfachen Operator wie ">>", aber zum Voranstellen.
Ich fürchte, es existiert nicht. Ich muss so etwas tun
mv myfile tmp cat myheader tmp> myfile
Etwas schlauer?
mktemp
? Sie können die temporäre Datei danach jederzeit bereinigen ...Antworten:
Der Hack unten war eine schnelle Antwort von der Stange, die funktionierte und viele positive Stimmen erhielt. Dann, als die Frage populärer wurde und mehr Zeit verging, berichteten empörte Leute, dass es irgendwie funktionierte, aber seltsame Dinge passieren konnten, oder es funktionierte einfach überhaupt nicht, so dass es eine Zeit lang wütend abgelehnt wurde. So ein Spaß.
Die Lösung nutzt die genaue Implementierung von Dateideskriptoren auf Ihrem System aus. Da die Implementierung zwischen den Nixen erheblich variiert, ist ihr Erfolg vollständig systemabhängig, definitiv nicht portierbar und sollte nicht für etwas verwendet werden, das auch nur vage wichtig ist.
Nun, mit all dem aus dem Weg war die Antwort:
Das Erstellen eines anderen Dateideskriptors für die Datei (
exec 3<> yourfile
), von wo aus in diese (>&3
) geschrieben wird, scheint das Lesen / Schreiben in demselben Dateidilemma zu überwinden. Funktioniert für mich bei 600K-Dateien mit awk. Es schlägt jedoch fehl, denselben Trick mit 'cat' zu versuchen.Wenn Sie das Präfix als Variable an awk (
-v TEXT="$text"
) übergeben, wird das Problem der wörtlichen Anführungszeichen überwunden, wodurch verhindert wird, dass dieser Trick mit 'sed' ausgeführt wird.quelle
Dies verwendet immer noch eine temporäre Datei, aber zumindest in einer Zeile:
Credit: BASH: Stellen Sie einer Datei einen Text / Zeilen vor
quelle
-
danachcat
?echo -n "text"
yourfile
es sich um einen Symlink handelt, wird dies nicht das tun, was Sie wollen.ed ist der Standard Editor! http://www.gnu.org/fun/jokes/ed.msg.html
quelle
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee: Es ist nicht garantiert, dass Ihre Methode funktioniert, und sie wird wahrscheinlich fehlschlagen, wenn Sie mehr als 4096 Byte voranstellen (zumindest passiert das mit gnu awk, aber ich nehme an, dass andere Implementierungen ähnliche Einschränkungen haben). In diesem Fall schlägt dies nicht nur fehl, sondern es tritt auch in eine Endlosschleife ein, in der die eigene Ausgabe gelesen wird, wodurch die Datei wächst, bis der gesamte verfügbare Speicherplatz belegt ist.
Probieren Sie es aus:
(Warnung: Töte es nach einer Weile oder es wird das Dateisystem füllen)
Darüber hinaus ist es sehr gefährlich, Dateien auf diese Weise zu bearbeiten, und es ist ein sehr schlechter Rat, als ob etwas passiert, während die Datei bearbeitet wird (Absturz, Festplatte voll). Es ist fast garantiert, dass sich die Datei in einem inkonsistenten Zustand befindet.
quelle
Ohne temporäre Datei nicht möglich, aber hier geht ein Oneliner
Sie können andere Tools wie ed oder perl verwenden, um dies ohne temporäre Dateien zu tun.
quelle
Es kann erwähnenswert sein, dass es oft eine gute Idee ist , die temporäre Datei mit einem Dienstprogramm wie mktemp sicher zu generieren , zumindest wenn das Skript jemals mit Root-Rechten ausgeführt wird. Sie könnten zum Beispiel Folgendes tun (erneut in Bash):
quelle
Wenn Sie dies auf Computern benötigen, die Sie steuern, installieren Sie das Paket "moreutils" und verwenden Sie "sponge". Dann können Sie tun:
quelle
{ echo "prepended text"; cat myfile } | sponge myfile
Mit einem Bash-Heredoc können Sie die Notwendigkeit einer tmp-Datei vermeiden:
Dies funktioniert, weil $ (cat myfile) ausgewertet wird, wenn das Bash-Skript ausgewertet wird, bevor die Katze mit Umleitung ausgeführt wird.
quelle
Angenommen, die Datei, die Sie bearbeiten möchten, ist my.txt
Und die Datei, die Sie voranstellen möchten, ist Header
Stellen Sie sicher, dass die Header-Datei eine letzte leere Zeile enthält.
Jetzt können Sie es mit voranstellen
Sie enden mit
Soweit ich weiß, funktioniert dies nur in "Bash".
quelle
this is the header
Am Ende hatte ich zwei Zeilen in my.txt. Selbst nachdem ich Bash aktualisiert4.3.42(1)-release
habe, erhalte ich das gleiche Ergebnis.<(...)
) schreibt. Daher gibt es keine Garantie, dass diesemy.txt
vollständig im Voraus gelesen wird , ohne die diese Technik nicht funktioniert.Wenn Sie versuchen, Dinge zu tun, die im Shell-Skript schwierig werden, würde ich dringend empfehlen, das Skript in einer "richtigen" Skriptsprache (Python / Perl / Ruby / etc) neu zu schreiben.
Wenn Sie einer Datei eine Zeile voranstellen, ist dies nicht über Piping möglich. Wenn Sie so etwas tun
cat blah.txt | grep something > blah.txt
, wird die Datei versehentlich gelöscht. Es gibt einen kleinen Dienstprogrammbefehl, densponge
Sie installieren können (Sie tun es)cat blah.txt | grep something | sponge blah.txt
und puffert den Inhalt der Datei und schreibt ihn dann in die Datei). Es ähnelt einer temporären Datei, aber Sie müssen dies nicht explizit tun. aber ich würde sagen, das ist eine "schlechtere" Anforderung als beispielsweise Perl.Es mag eine Möglichkeit geben, dies über awk oder ähnliches zu tun, aber wenn Sie ein Shell-Skript verwenden müssen, denke ich, dass eine temporäre Datei bei weitem die einfachste (/ einzige?) Möglichkeit ist.
quelle
Wie Daniel Velkov vorschlägt, verwenden Sie Tee.
Für mich ist das eine einfache, intelligente Lösung:
quelle
EDIT: Das ist kaputt. Siehe Seltsames Verhalten beim Voranstellen einer Datei mit Katze und Tee
Die Problemumgehung für das Überschreibproblem lautet
tee
:quelle
Die, die ich benutze. In diesem Fall können Sie die Reihenfolge, zusätzliche Zeichen usw. so angeben, wie Sie es möchten:
PS: Nur funktioniert es nicht, wenn Dateien Text mit Backslash enthalten, da sie als Escape-Zeichen interpretiert werden
quelle
Meistens zum Spaß / Shell Golf, aber
wird den Trick machen, und es gibt keine Pipelines oder Umleitungen. Natürlich ist vi / ex nicht wirklich für den nicht interaktiven Gebrauch gedacht, daher blinkt vi kurz auf.
quelle
Warum nicht einfach den Befehl ed verwenden (wie bereits von fluffle hier vorgeschlagen)?
ed liest die gesamte Datei in den Speicher und führt automatisch eine direkte Dateibearbeitung durch!
Also, wenn Ihre Datei nicht so groß ist ...
Eine weitere Problemumgehung wäre die Verwendung offener Dateihandles, wie von Jürgen Hötzel in der Umleitungsausgabe von seds / c / d / 'myFile zu myFile vorgeschlagen
All dies könnte natürlich in einer einzigen Zeile stehen.
quelle
Eine Variante der Lösung von cb0 für "keine temporäre Datei", um festen Text voranzustellen:
Dies hängt wiederum von der Ausführung der Sub-Shell ab - der (..) -, um zu vermeiden, dass die Katze sich weigert, dieselbe Datei für die Eingabe und Ausgabe zu haben.
Hinweis: Diese Lösung hat mir gefallen. Auf meinem Mac geht jedoch die Originaldatei verloren (dachte, es sollte nicht, aber es tut es). Dies könnte behoben werden, indem Sie Ihre Lösung wie folgt schreiben: echo "text to prepend" | cat - file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified
quelle
Folgendes habe ich entdeckt:
quelle
quelle
WARNUNG: Dies erfordert etwas mehr Arbeit, um die Anforderungen des OP zu erfüllen.
Es sollte eine Möglichkeit geben, den sed-Ansatz von @shixilun trotz seiner Bedenken zum Laufen zu bringen. Es muss ein Bash-Befehl vorhanden sein, um Leerzeichen beim Lesen einer Datei in eine sed-Ersatzzeichenfolge zu umgehen (z. B. Zeilenumbruchzeichen durch '\ n' ersetzen. Shell-Befehle
vis
undcat
können nicht druckbare Zeichen verarbeiten, jedoch keine Leerzeichen, sodass die OPs nicht gelöst werden Problem:schlägt aufgrund der rohen Zeilenumbrüche im Ersatzskript fehl, denen ein Zeilenfortsetzungszeichen () vorangestellt werden muss und möglicherweise ein & folgt, um die Shell und sed glücklich zu halten, wie diese SO-Antwort
sed
hat eine Größenbeschränkung von 40 KB für nicht globale Such-Ersetzungs-Befehle (kein nachfolgendes / g nach dem Muster), sodass wahrscheinlich die beängstigenden Pufferüberlaufprobleme von awk vermieden werden, vor denen anonym gewarnt wurde.quelle
quelle
Mit $ (Befehl) können Sie die Ausgabe eines Befehls in eine Variable schreiben. Also habe ich es in drei Befehlen in einer Zeile und ohne temporäre Datei gemacht.
quelle
Wenn Sie eine große Datei (in meinem Fall einige hundert Kilobyte) und Zugriff auf Python haben, ist dies viel schneller als
cat
Pipe-Lösungen:python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'
quelle
Eine Lösung mit
printf
:Sie könnten auch tun:
In diesem Fall müssen Sie jedoch sicherstellen, dass es
%
nirgendwo etwas gibt, einschließlich des Inhalts der Zieldatei, da dies interpretiert werden kann und Ihre Ergebnisse vermasseln kann.quelle
echo
scheint eine sicherere Option zu sein.echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
, nicht vor der ZieldateiSie können die Perl-Befehlszeile verwenden:
Wobei -i einen Inline-Ersatz für die Datei erstellt und -0777 die gesamte Datei schlürft und ^ nur mit dem Anfang übereinstimmt. -pe druckt alle Zeilen
Oder wenn my_header eine Datei ist:
Wobei das / e eine Auswertung des Codes in der Ersetzung zulässt.
quelle
Dabei ist "my_file" die Datei, der "my_string" vorangestellt werden soll.
quelle
Ich mag @ fluffles ed Ansatz am besten. Schließlich sind die Befehlszeilenwechsel eines Tools im Vergleich zu Skripteditorbefehlen hier im Wesentlichen dasselbe. Ich sehe nicht, dass eine Skripteditor-Lösung "Sauberkeit" weniger oder so ist.
Hier ist mein Einzeiler,
.git/hooks/prepare-commit-msg
an den eine In-Repo-.gitmessage
Datei angehängt wird , um Nachrichten festzuschreiben:Beispiel
.gitmessage
:Ich mache
1r
stattdessen0r
, weil dadurch die leere schreibfertige Zeile über der Datei aus der Originalvorlage verbleibt. Setzen Sie dann keine leere Zeile auf Ihre,.gitmessage
da Sie am Ende zwei leere Zeilen haben.-s
unterdrückt die Ausgabe von Diagnoseinformationen von ed.Im Zusammenhang damit habe ich festgestellt, dass es für Vim-Fans auch gut ist, Folgendes zu haben:
quelle
Variablen, ftw?
quelle
Ich denke, dies ist die sauberste Variante von ed:
als eine Funktion:
quelle
Wenn Sie in BASH Skripte erstellen, können Sie Folgendes tun:
Das ist eigentlich in dem komplexen Beispiel, das Sie selbst in Ihrer eigenen Frage gepostet haben.
quelle
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
unterscheidet sich jedoch ausreichend von meiner Antwort, sodass es sich um eine eigene Antwort handeln sollte.IMHO gibt es keine Shell-Lösung (und wird es auch nie geben), die unabhängig von der Größe der beiden Dateien
myheader
und konsistent und zuverlässig funktioniertmyfile
. Der Grund dafür ist, dass Sie dies tun möchten, ohne zu einer temporären Datei zurückzukehren (und ohne dass die Shell stillschweigend zu einer temporären Datei zurückkehrt, z. B. durch Konstrukte wieexec 3<>myfile
Piping totee
usw.).Die "echte" Lösung, nach der Sie suchen, muss mit dem Dateisystem herumspielen. Daher ist sie im Benutzerbereich nicht verfügbar und plattformabhängig: Sie möchten den verwendeten Dateisystemzeiger
myfile
auf den aktuellen Wert des Dateisystemzeigers ändern fürmyheader
und ersetzen Sie im Dateisystem dasEOF
vonmyheader
durch einen verketteten Link zur aktuellen Dateisystemadresse, auf die verwiesen wirdmyfile
. Dies ist nicht trivial und kann offensichtlich nicht von einem Nicht-Superuser und wahrscheinlich auch nicht vom Superuser durchgeführt werden ... Spielen Sie mit Inodes usw.Sie können dies jedoch mehr oder weniger mit Loop-Geräten vortäuschen. Siehe zum Beispiel diesen SO-Thread .
quelle