Wie füge ich Text am Anfang einer Datei in Bash ein?

285

Hallo, ich möchte einer Datei Text voranstellen. Zum Beispiel möchte ich Aufgaben am Anfang einer todo.txt-Datei hinzufügen. Mir ist bewusst, echo 'task goes here' >> todo.txtaber das fügt die Zeile an das Ende der Datei (nicht was ich will).

user479534
quelle
2
Es gibt keine effiziente Möglichkeit, dies für große Dateien zu tun: unix.stackexchange.com/questions/87772/…
Ciro Santilli Am
@ould Sie einen Blick auf diese Methode superuser.com/a/1352628/11116
Evan Carroll

Antworten:

374
echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt

oder

sed -i '1s/^/task goes here\n/' todo.txt

oder

sed -i '1itask goes here' todo.txt
Dennis Williamson
quelle
4
der erste funktioniert super! Würde es Ihnen etwas ausmachen, die Logik zu erklären? Ich bin mir nicht sicher, wie ich die Syntax interpretieren soll.
user479534
44
@ user8347: Pipe ( |) die Nachricht ( echo '...'), für catdie -(Standardeingabe) als erste und todo.txtals zweite Datei verwendet wird . catconCATenates mehrere Dateien. Senden Sie die Ausgabe ( >) an eine Datei mit dem Namen temp. Wenn es keine Fehler gibt ( &&), catbenennen Sie mvdie tempDatei um ( ) und kehren Sie zur ursprünglichen Datei zurück ( todo.txt).
Dennis Williamson
1
@itaifrenkel: Ich müsste sehen, was Sie getan haben, aber wenn catein Backslash n empfangen wird, wird es nicht in eine neue Zeile konvertiert. Etwas anderes muss das getan haben. catVersuchen hexdump -CSie stattdessen , per Piping in zu prüfen, ob Sie tatsächlich Backslash und n senden oder ob es sich um eine neue Zeile handelt. Sie können auch versuchen cat -e, Zeilenenden anzuzeigen.
Dennis Williamson
1
Mit 2 und 3 (3 scheint mir einfacher zu sein) können Sie vielen Dateien gleichzeitig Text voranstellen .
Felix
4
@Kira: Das 1bedeutet, dass der nächste Befehl nur in Zeile 1 der Datei ausgeführt wird und der iBefehl Einfügen lautet. Schauen Sie in der Manpage unter "Adressen" und unter "Null- oder Einadressenbefehle" nach.
Dennis Williamson
73

Eine meiner Meinung nach einfachere Option ist:

echo -e "task goes here\n$(cat todo.txt)" > todo.txt

Dies funktioniert, weil der Befehl innerhalb von $(...)ausgeführt wird, bevor er todo.txtmit überschrieben wird> todo.txt

Während die anderen Antworten gut funktionieren, fällt es mir viel leichter, mich daran zu erinnern, weil ich jeden Tag Echo und Katze benutze.

BEARBEITEN: Diese Lösung ist eine sehr schlechte Idee, wenn es irgendwelche Backslashes gibt todo.txt, weil sie dank des -eFlag-Echos interpretiert werden. Eine andere, weitaus einfachere Möglichkeit, Zeilenumbrüche in die Vorwortzeichenfolge einzufügen, ist ...

echo "task goes here
$(cat todo.txt)" > todo.txt

... einfach um Zeilenumbrüche zu benutzen. Sicher, es ist kein Einzeiler mehr, aber realistisch gesehen war es auch vorher kein Einzeiler. Wenn Sie dies innerhalb eines Skripts tun und sich Gedanken über das Einrücken machen (z. B. wenn Sie dies innerhalb einer Funktion ausführen), gibt es ein paar Problemumgehungen, um dies noch gut anzupassen, einschließlich, aber nicht beschränkt auf:

(echo 'task goes here' && cat todo.txt) > todo.txt
echo 'task goes here'$'\n'"$(cat todo.txt)" > todo.txt

Wenn Sie sich darüber Gedanken machen, ob eine neue Zeile am Ende von hinzugefügt wird, todo.txtverwenden Sie diese nicht. Na ja, bis auf den vorletzten. Das bringt nichts mit dem Ende.

John Alberts
quelle
1
Ich werde $ (...) überhaupt nicht hinrichten lassen.
SCL
2
Das funktioniert vielleicht besser (oder überhaupt) mit doppelten Anführungszeichen anstelle von einfachen…
ℝaphink
5
Werden die -eEscape-Sequenzen nicht auch in die Datei todo.txt konvertiert?
mk12
2
Problemumgehungen ergeben -> cat: <Zieldateiname>: Eingabedatei ist Ausgabedatei ...
hier
printf ist plattformübergreifend wesentlich konsistenter und sollte im Allgemeinen reibungsloser funktionieren als echo -e
Peter Berg
28

Die moreutilshaben ein schönes Tool namens sponge:

echo "task goes here" | cat - todo.txt | sponge todo.txt

Es wird STDIN "aufsaugen" und dann in die Datei schreiben, was bedeutet, dass Sie sich keine Gedanken über temporäre Dateien machen und diese verschieben müssen.

Sie können moreutilsmit vielen Linux-Distributionen über apt-get install moreutilsoder unter OS X mit Homebrew mit brew install moreutils.

slhck
quelle
Ich würde gehen für (echo 'ble'; cat todo.txt):-)
Ciro Santilli 新疆 新疆 中心 法轮功 法轮功 六四
11

Sie können Vim im Ex-Modus verwenden:

ex -s -c '1i|task goes here' -c x todo.txt
  1. 1 erste Zeile auswählen

  2. i einfügen

  3. x speichern und schließen

Steven Penny
quelle
5

Sie können eine neue temporäre Datei erstellen.

echo "new task" > new_todo.txt
cat todo.txt >> new_todo.txt
rm todo.txt
mv new_todo.txt todo.txt

Sie können auch sedoder verwenden awk. Aber im Grunde passiert das Gleiche.

Keith
quelle
1
Angenommen, Sie haben keinen Speicherplatz mehr, sodass new_todo.txtnur ein Teil davon geschrieben wird. Ihre Lösung scheint die Originaldatei zu verlieren.
NPE
Wem geht der Speicherplatz aus? ;-) Es ist nur ein einfaches Beispiel.
Keith
2
@Keith Jemand, der an einer VM arbeitet und nicht erwartet hat, dass er ein besonders großes virtuelles Laufwerk benötigt. Oder jemand, der eine große Datei verschiebt. In jedem Fall sind Verzeichnisberechtigungen das eigentliche Argument dafür. Wenn Sie keine Berechtigung zum Erstellen neuer Dateien im angegebenen Verzeichnis haben, ist der einzige Befehl, der in Ihrem Skript erfolgreich ausgeführt wird, der rmder Originaldatei.
Parthian Shot
3

Wenn die Textdatei klein genug ist, um in den Arbeitsspeicher zu passen, müssen Sie keine temporäre Datei erstellen, durch die sie ersetzt werden soll. Sie können alles in den Speicher laden und in die Datei zurückschreiben.

echo "$(echo 'task goes here' | cat - todo.txt)" > todo.txt

Es ist unmöglich, Zeilen an den Anfang der Datei zu setzen, ohne die gesamte Datei zu überschreiben.

Rucent88
quelle
Nur um die naheliegende Frage zu stellen: Wo ist die Zeichenbeschränkung für Shell-Variablen?
Nixda
Soweit mir bekannt ist, ist es nur durch den verfügbaren Speicher begrenzt. Ich habe Variablen weit über 100 MB in den Speicher gefüllt. text=$(cat file). Achten
Rucent88
2

Sie können am Anfang einer Datei keinen Inhalt einfügen. Das einzige, was Sie tun können, ist entweder vorhandenen Inhalt zu ersetzen oder Bytes nach dem aktuellen Dateiende anzufügen.

Für jede Lösung Ihrer Frage muss dann eine temporäre Datei (oder ein Zwischenspeicher) erstellt werden (im Speicher oder auf der Festplatte), die letztendlich die ursprüngliche Datei überschreibt.

Achten Sie darauf, dass beim Erstellen der neuen Datei keine Daten verloren gehen, da die ursprüngliche Datei erhalten bleibt, falls das Dateisystem während des Vorgangs voll ist. z.B:

cat <(echo task go there) todo.txt > todo.txt.new && mv todo.txt.new todo.txt
jlliagre
quelle
Downvoter sind herzlich eingeladen, ihre Motivation zu erläutern. Keine der verbleibenden Antworten, einschließlich der akzeptierten, widerspricht irgendetwas in meiner Antwort.
Jlliagre
Dies ist schwierig zu analysieren, da die <...> Klammern aussehen, von denen ich annehme, dass sie es nicht sind. Ein Leerzeichen zwischen dem <und dem (könnte helfen?
Dumbledad
Das funktioniert bei mir nicht. echo HOME=\"/g/Users/timregan/\" | cat - 'F:\Program Files\Git\etc\profile'funktioniert, cat <echo HOME=\"/g/Users/timregan/\" 'F:\Program Files\Git\etc\profile'gibt aber den Fehler "Echo: Keine solche Datei oder Verzeichnis"
Dumbledad
@ Dumbledad Du überdenkst meine Antwort. Es gibt nichts, was Sie darin analysieren könnten. Ein Leerzeichen zwischen <und (würde die Syntax sprengen. Trycat <(echo HOME=\"/g/Users/timregan/\") 'F:\Program Files\Git\etc\profile'
jlliagre
1

Sie können verwenden tee:

echo 'task goes here' | cat - todo.txt | tee todo.txt
Radu Rădeanu
quelle
3
Nein, Sie können nicht askubuntu.com/a/752451
Steven Penny
0

GitBash + Windows10 + Multline :

In dieser Version können Sie mehrzeilige Zeichenfolgen verwenden .

##############################################
## This section for demo purpose only,      ##
## So you can save entire file as           ##
## whatever.sh and run it.                  ##
##                                          ##
##############################################
> MY_TARGET_FILE.txt ##Make Or Clear File
echo "[STARTER_CONTENT]" >> MY_TARGET_FILE.txt
##############################################

## Below is main code:

##################################################
TARGET_FILE_VARIABLE="MY_TARGET_FILE.txt"
ADD_TO_HEAD_VARIABLE=$(cat << "HEREDOC_HEAD_TEXT"
//|  +-------------------------------------+   |//
//|  |                                     |   |//
//|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
//|  |                                     |   |//
//|  +-------------------------------------+   |//
HEREDOC_HEAD_TEXT
)
##################################################
TAR=$TARGET_FILE_VARIABLE                       ##
TEX=$ADD_TO_HEAD_VARIABLE                       ##
echo "$TEX" | cat - $TAR > TEMP && mv TEMP $TAR ##
##################################################

## Expected contents of MY_TARGET_FILE.txt :
## //|  +-------------------------------------+   |//
## //|  |                                     |   |//
## //|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
## //|  |                                     |   |//
## //|  +-------------------------------------+   |//
## [STARTER_CONTENT]
J MADISON
quelle