Wie kann man eine Datei unter Linux aus der Shell an eine andere anhängen?

418

Ich habe zwei Dateien: file1und file2. Wie füge ich den Inhalt von an file2an, file1damit der Inhalt von file1den Prozess beibehält?

asir
quelle

Antworten:

610

Verwenden Sie die integrierte Bash-Umleitung (tldp) :

cat file2 >> file1
David
quelle
2
Wie machst du das? Die Zieldatei gehört dir nicht und du musst sudo verwenden?
Bijay Rungta
1
@ BijayRungta: Es hört sich so an, als hättest du deine eigene Frage beantwortet. Sie würden sudoden catBefehl vorab anhängen (und Anmeldeinformationen eingeben, wenn Sie dazu aufgefordert werden).
David
Sie müssen ... chmod 777 / etc / default / docker, um sich Schreibberechtigungen für diese Datei zu erteilen - stellen Sie sicher, dass Sie die alten Dateiberechtigungen wiederherstellen, sobald Sie fertig sind
danday74
1
@Sigur: Sofern es keine Möglichkeit gibt, die Ausgabe auf zwei Dateien gleichzeitig zu leiten, würde dies zwei Aufrufe des Befehls beinhalten.
David
2
@Sigur oder schauen Sie sich das teeProgramm an : cat 1 | tee -a 2 3. Sie können nach dem --append(oder -akurz) Wechsel beliebig viele Dateien ablegen.
Stefan van den Akker
291

cat file2 >> file1

Der >>Operator hängt die Ausgabe an die benannte Datei an oder erstellt die benannte Datei, wenn sie nicht vorhanden ist.

cat file1 file2 > file3

Dadurch werden zwei oder mehr Dateien zu einer verknüpft. Sie können so viele Quelldateien haben, wie Sie benötigen. Zum Beispiel,

cat *.txt >> newfile.txt

Update 20130902
In den Kommentaren schlägt eumiro vor, es nicht zu versuchen cat file1 file2 > file1. Der Grund, warum dies möglicherweise nicht zum erwarteten Ergebnis führt, ist, dass die Datei, die die Umleitung empfängt, vorbereitet wird, bevor der Befehl links von >ausgeführt wird. In diesem Fall wird zuerst die file1Länge Null abgeschnitten und für die Ausgabe geöffnet. Anschließend catversucht der Befehl, die Datei mit der Länge Null und den Inhalt von file2into zu verketten file1. Das Ergebnis ist, dass der ursprüngliche Inhalt von file1verloren geht und an seiner Stelle eine Kopie steht, von file2der wahrscheinlich nicht das ist, was erwartet wurde.

Update 20160919
In den Kommentaren schlägt tpartee vor, auf Hintergrundinformationen / Quellen zu verlinken. Als maßgebliche Referenz verweise ich den freundlichen Leser auf die sh-Manpage unter linuxcommand.org, auf der es heißt:

Bevor ein Befehl ausgeführt wird, können seine Eingabe und Ausgabe unter Verwendung einer von der Shell interpretierten speziellen Notation umgeleitet werden.

Das sagt dem Leser zwar, was er wissen muss, aber es ist leicht zu übersehen, wenn Sie nicht danach suchen und die Aussage Wort für Wort analysieren. Das wichtigste Wort hier ist "vorher". Die Umleitung ist abgeschlossen (oder schlägt fehl), bevor der Befehl ausgeführt wird.

Im Beispielfall cat file1 file2 > file1führt die Shell zuerst die Umleitung durch, sodass die E / A-Handles in der Umgebung vorhanden sind, in der der Befehl ausgeführt wird, bevor er ausgeführt wird.

Eine freundlichere Version, in der die Priorität der Umleitung ausführlich behandelt wird, finden Sie auf der Website von Ian Allen in Form von Linux-Kursunterlagen. Seine Seite mit E / A-Umleitungsnotizen hat viel zu diesem Thema zu sagen, einschließlich der Beobachtung, dass die Umleitung auch ohne Befehl funktioniert. Weitergabe an die Shell:

$ >out

... erstellt eine leere Datei mit dem Namen out. Die Shell richtet zuerst die E / A-Umleitung ein, sucht dann nach einem Befehl, findet keinen und schließt den Vorgang ab.

T.Rob
quelle
17
@asir - versuchen cat file1 file2 > file1Sie es nicht - das wird nicht so funktionieren, wie Sie es wahrscheinlich erwarten.
Eumiro
5
Genau das braucht er. Er sagt "ohne die aktuelle Datei1 zu überschreiben." Die ersten drei Antwortenden haben diesen Teil der Frage vollständig ignoriert und einen Befehl vorgeschlagen, mit >>dem die Datei geändert wirdfile1 . T.Rob hat seine Antwort weit überlegen erklärt, anstatt nur zu rennen, um etwas einzureichen, das tatsächlich falsch war. Basierend auf dem Text der Frage glaube ich, dass dies cat file1 file2 > file3der geeignete Befehl ist, nach dem @asir gesucht hat.
dm78
Danke für die freundlichen Worte, David! Was @eumiro oben hervorhebt, aber nicht ins Detail geht, ist, dass die Operation rechts von >zuerst ausgeführt wird. cat file1 file2 > file1Wenn Sie also ausführen , wird zuerst file1versucht, die Datei mit der Länge Null auf sich selbst zu kopieren. Dies ist sinnvoll, wenn Sie über die Reihenfolge nachdenken, in der die Operationen stattfinden könnten und sollten, ist jedoch so subtil, dass viele Menschen überrascht werden. Wenn nichts anderes, haben eumiro und Sie eine weitere Verbesserung der Antwort veranlasst. Dank dafür!
T. Rob
Auch nicht versuchen Katze file1 >> file1, dies bewirkt , dass die Datei rekursiv neu geschrieben werden, ich dies versehentlich tun und nur innerhalb von wenigen Sekunden, 50 Millionen Zeilen haben , um die Datei von nur vorher ein paar Dutzend Zeilen gesetzt worden.
Hendra Uzia
Wenn die "neue Datei" bereits vorhanden ist, wird >> sie an die Datei angehängt und > ersetzt die Datei , um sie etwas präziser zu gestalten .
Rinogo
43

Hinweis : Wenn Sie sudo verwenden müssen , gehen Sie folgendermaßen vor:

sudo bash -c 'cat file2 >> file1'

Die übliche Methode zum einfachen Voranstellen sudodes Befehls schlägt fehl, da die Eskalation von Berechtigungen nicht auf die Ausgabeumleitung übertragen wird.

jdunk
quelle
6
Eine andere gängige Redewendung dafür istcat file2 | sudo tee -a file1 > /dev/null
ianw
28

Versuchen Sie diesen Befehl:

cat file2 >> file1
Eumiro
quelle
13

Nur als Referenz bietet die Verwendung von ddrescue eine unterbrechbare Möglichkeit, die Aufgabe zu erfüllen, wenn Sie beispielsweise große Dateien haben und eine Pause einlegen und zu einem späteren Zeitpunkt fortfahren müssen:

ddrescue -o $(wc --bytes file1 | awk '{ print $1 }') file2 file1 logfile

Das logfileist das Wichtige. Sie können den Vorgang mit unterbrechen Ctrl-Cund fortsetzen, indem Sie genau denselben Befehl erneut angeben. Ddrescue liest logfileund setzt ihn dort fort, wo er aufgehört hat. Das -o AFlag weist ddrescue an, mit Byte A in der Ausgabedatei ( file1) zu beginnen. Extrahiert also wc --bytes file1 | awk '{ print $1 }'einfach die Größe file1in Bytes (Sie können die Ausgabe einfach einfügen, lswenn Sie möchten).

Wie von ngks in den Kommentaren hervorgehoben, besteht der Nachteil darin, dass ddrescue wahrscheinlich nicht standardmäßig installiert wird, sodass Sie es manuell installieren müssen. Die andere Komplikation ist, dass es zwei Versionen von ddrescue gibt, die sich möglicherweise in Ihren Repositories befinden: Weitere Informationen finden Sie in dieser Askubuntu-Frage . Die gewünschte Version ist GNU ddrescue, und auf Debian-basierten Systemen lautet das Paket mit dem Namen gddrescue:

sudo apt install gddrescue

Für andere Distributionen überprüfen Sie Ihr Paketverwaltungssystem auf die GNU- Version von ddrescue.

Zorawar
quelle
1
Für neue Benutzer: ddrescue ist ein GNU-Tool, das jedoch möglicherweise nicht auf Ihrem Linux-, Mac- oder anderen Unix-ähnlichen System vorhanden ist. ddrescue scheint von POSIX oder einem anderen Standard nicht benötigt zu werden.
2

Eine andere Lösung:

cat file1 | tee -a file2

tee hat den Vorteil, dass Sie an beliebig viele Dateien anhängen können, zum Beispiel:

cat file1 | tee -a file2 file3 file3

wird der Inhalt anhängen file1zu file2, file3und file4.

Von der Manpage:

-a, --append
       append to the given FILEs, do not overwrite
Stefan van den Akker
quelle
0

catkann die einfache Lösung sein, aber das wird sehr langsam, wenn wir große Dateien zusammenfassen, find -printist es, Sie zu retten, obwohl Sie cat einmal verwenden müssen.

amey@xps ~/work/python/tmp $ ls -lhtr
total 969M
-rw-r--r-- 1 amey amey 485M May 24 23:54 bigFile2.txt
-rw-r--r-- 1 amey amey 485M May 24 23:55 bigFile1.txt

 amey@xps ~/work/python/tmp $ time cat bigFile1.txt bigFile2.txt >> out.txt

real    0m3.084s
user    0m0.012s
sys     0m2.308s


amey@xps ~/work/python/tmp $ time find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1

real    0m2.516s
user    0m0.028s
sys     0m2.204s
Amey Jadiye
quelle
Die Zeitersparnis, die Sie für Ihren Kombinationsbefehl find / cat melden, besteht darin, dass Sie nur den Befehl find zeitlich festlegen, bei dem die Namen der Dateien ausgedruckt werden. Versuchen Sie, den gesamten Befehl wie time (find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1)folgt zu steuern : und er sollte ähnliche Ergebnisse wie der Befehl nur für Katzen liefern.
JoshMc
0

Sie können dies auch ohne tun cat, obwohl dies ehrlich gesagt catbesser lesbar ist:

>> file1 < file2

Das >>hängt STDIN an file1und die <Dumps file2an STDIN .

Alok Singh
quelle
@ user202729 Du hast recht, es funktioniert nicht in Bash. Es funktioniert in zsh.
Alok Singh