Wie kopiere ich den Inhalt jeder Datei in einer Liste in eine andere Datei?

15

Ich habe eine Liste von Dateinamen in einer Datei namens list_of_files.txt.

Ich möchte den Inhalt jeder Datei in dieser Liste in eine andere Datei mit dem Namen kopieren all_compounds.sdf.

Wie soll ich das von der Kommandozeile aus machen?

Ramita Rajaa
quelle

Antworten:

20

Verwenden Sie keine einfache Befehlsersetzung, um Dateinamen abzurufen (dies kann leicht zu Leerzeichen und anderen Sonderzeichen führen). Verwenden Sie etwas wie xargs:

xargs -d '\n' -a list_of_files.txt cat > all_compounds.sdf

Oder eine while readSchleife:

while IFS= read -r file; do cat "$file"; done < list_of_files.txt > all_compounds.sdf

Um die Befehlsersetzung sicher zu verwenden, stellen Sie mindestens IFSnur die Zeilenumbrüche ein und deaktivieren Sie das Globbing (Platzhaltererweiterung):

(set -f; IFS=$'\n'; cat $(cat list_of_files.txt) > all_compounds.sdf)

Die umgebenden Klammern ()sollen dies in einer Subshell ausführen, damit Ihre aktuelle Shell von diesen Änderungen nicht betroffen ist.

muru
quelle
14

Schnell und dreckig unterwegs ...

cat $(cat list_of_files.txt) >> all_compounds.sdf

Bitte beachten Sie: Dies funktioniert nur, wenn sich die Dateinamen in Ihrer Liste sehr gut verhalten. Wenn Leerzeichen, Zeilenumbrüche oder Zeichen mit besonderer Bedeutung für die Shell auftauchen, kann es zu Fehlern kommen. Verwenden Sie stattdessen diese Antwort, um zuverlässige Ergebnisse zu erhalten.

Anmerkungen

  • catcon cat enates files. Es druckt auch deren Inhalt.
  • Mit der Befehlsersetzung command2 $(command1)können Sie die Ausgabe von command1( cat list...) an command2( cat) übergeben, die die Dateien verkettet.
  • Verwenden Sie dann die Umleitung >>, um die Ausgabe an eine Datei zu senden, anstatt an stdout zu drucken. Wenn Sie die Ausgabe sehen möchten, verwenden Sie teestattdessen:

    cat $(cat list_of_files.txt) | tee -a all_compounds.sdf

(Ich habe >>anstelle von >und teemit dem -aSchalter verwendet, falls Ihre Datei bereits vorhanden ist. Dies wird an die Datei angehängt , anstatt sie zu überschreiben, falls sie bereits vorhanden ist.)

Zanna
quelle
1
@ Zanna zitieren die Befehlsersetzungen, um Worttrennung zu vermeiden, wie"$(cat list_of_files.txt)"
Sergiy Kolodyazhnyy
4
@ Serg Wenn die Wortteilung nicht durchgeführt wird, catwird die gesamte Liste als ein Argument abgerufen .
muru
@muru OK, wie gehen wir dann mit Dateinamen um, die Leerzeichen enthalten?
Sergiy Kolodyazhnyy
1
@ Serg IFS entsprechend einstellen - siehe letzten Absatz meiner Antwort
muru
4

Während GNU awkein Textverarbeitungsprogramm ist, können externe Shell-Befehle über einen system()Aufruf ausgeführt werden. Das können wir so zu unserem Vorteil nutzen:

$ awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt                                                        

Die Idee hier ist einfach: Wir lesen die Datei Zeile für Zeile und erstellen aus jeder Zeile eine formatierte Zeichenfolge cat "File name.txt", die dann an übergeben wird system().

Und hier ist es in Aktion:

$ ls
file1.txt  file2.txt  file3 with space.txt  file_list.txt


$ awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt                                                        
Hi, I'm file2
Hi, I'm file1
Hi, I'm file3

Wir haben dort also schon den größten Teil der Aufgabe erledigt - wir haben alle Dateien auf der Liste gedruckt. Der Rest ist einfach: Leiten Sie die endgültige Ausgabe in die Datei mit dem >Operator in die Zusammenfassungsdatei um.

awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt > output.txt
Sergiy Kolodyazhnyy
quelle