Leiten Sie die Ausgabe von cat an cURL weiter, um eine Liste der Dateien herunterzuladen


83

Ich habe eine Liste URLs in einer Datei namens urls.txt. Jede Zeile enthält 1 URL. Ich möchte alle Dateien gleichzeitig mit cURL herunterladen. Ich kann anscheinend nicht den richtigen Einzeiler finden.

Ich habe es versucht:

$ cat urls.txt | xargs -0 curl -O

Aber das gibt mir nur die letzte Datei in der Liste.


10
for i in $(cat urls.txt) ; do curl -O $i ; done
Bkconrad

1
Danke, @bkconrad. Ich hatte Probleme mit Newlines unter Windows, ich habe es behoben mit tr:for i in $(cat urls.txt) ; do curl -O $(echo $i | tr '\r' ' ') ; done
Biphobe

Antworten:


137

Das funktioniert bei mir:

$ xargs -n 1 curl -O < urls.txt

Ich bin in FreeBSD. Ihre Xargs funktionieren möglicherweise anders.

Beachten Sie, dass hier sequentielle curls ausgeführt werden, die Sie möglicherweise als unnötig schwer ansehen. Wenn Sie einen Teil dieses Overheads sparen möchten, kann Folgendes in bash funktionieren:

$ mapfile -t urls < urls.txt
$ curl ${urls[@]/#/-O }

Dadurch wird Ihre URL-Liste in einem Array gespeichert und das Array um Optionen erweitert, curldamit Ziele heruntergeladen werden. Der curlBefehl kann mehrere URLs verwenden und alle abrufen, wobei die vorhandene Verbindung (HTTP / 1.1) wiederhergestellt wird. Er benötigt jedoch -Ovor jeder Option die Option, um jedes Ziel herunterzuladen und zu speichern . Beachten Sie, dass Zeichen in einigen URLs] möglicherweise maskiert werden müssen, um eine Interaktion mit Ihrer Shell zu vermeiden.

Oder wenn Sie eine POSIX-Shell anstelle von Bash verwenden:

$ curl $(printf ' -O %s' $(cat urls.txt))

Dies beruht auf printfdem Verhalten des Wiederholens des Formatmusters, um die Liste der Datenargumente zu erschöpfen. printfDies werden nicht alle eigenständigen Benutzer tun.

Beachten Sie, dass diese Nicht-Xargs-Methode möglicherweise auch gegen Systembeschränkungen für sehr große Listen von URLs stößt. Untersuchen Sie ARG_MAX und MAX_ARG_STRLEN, wenn dies ein Problem darstellt .


Dies scheint zu funktionieren, aber es gibt mir nur eine 125-Byte-HTML-Datei, die den Namen der Datei enthält, nicht den tatsächlichen Dateiinhalt.
Finch

1
Ah ich sehe. Da es sich um eine Weiterleitung handelte, musste ich die -LOption hinzufügen curl.
Finch

4
Danke für den Tipp! Das funktioniert auf meinem Mac, aber ich bevorzuge die Pipeline-Version cat urls.txt | xargs -n 1 curl -O;-)
Orzechow

@Pio, fair genug, es funktioniert alles, aber für Ihr Lesevergnügen unix.stackexchange.com/questions/16279/…
ghoti

Das hat super geklappt!. Allerdings habe ich dies in Git Bash unter Windows verwendet und es mochte keine \rZeichen in der Textdatei.
James McDonnell

33

Eine sehr einfache Lösung wäre die folgende: Wenn Sie eine Datei 'file.txt' wie haben

url="http://www.google.de"
url="http://www.yahoo.de"
url="http://www.bing.de"

Dann können Sie Curl verwenden und einfach tun

curl -K file.txt

Und curl ruft alle in Ihrer file.txt enthaltenen URLs auf!

Wenn Sie also die Kontrolle über Ihr Eingabedateiformat haben, ist dies möglicherweise die einfachste Lösung für Sie!


1
Wird dies HTTP Keep-Alive verwenden?
William Entriken

@FullDecent Es verwendet die Verbindung auf diese Weise wieder
Allan Deamon

14

Oder Sie könnten einfach Folgendes tun:

cat urls.txt | xargs curl -O

Sie müssen den -IParameter nur verwenden , wenn Sie die cat-Ausgabe in die Mitte eines Befehls einfügen möchten.


1
Ich bin mir nicht sicher, warum dies abgelehnt wird, aber es funktioniert perfekt für mich, aber anstelle einer flachen Textdatei für die Eingabe hatte ich die Ausgabe von grep.
Rob

1
Wahrscheinlich herabgestimmt, weil es falsch ist. Die -oOption für Curl gibt eine Ausgabedatei als Argument an. Andere Antworten empfehlen -O, die curl anweisen, den lokalen Namen basierend auf dem Remote-Namen der Datei zu bestimmen.
Ghoti

8

xargs -P 10 | curl

GNU xargs -Pkann mehrere curlProzesse gleichzeitig ausführen . ZB um 10Prozesse auszuführen :

xargs -P 10 -n 1 curl -O < urls.txt

Dies beschleunigt den Download um das 10-fache, wenn Ihre maximale Download-Geschwindigkeit nicht erreicht wird und der Server die IPs nicht drosselt. Dies ist das häufigste Szenario.

Stellen Sie es einfach nicht -Pzu hoch ein, sonst ist Ihr RAM möglicherweise überlastet.

GNU parallelkann ähnliche Ergebnisse erzielen.

Der Nachteil dieser Methoden ist, dass sie nicht für alle Dateien eine einzige Verbindung verwenden. Was curlpassiert, wenn Sie mehrere URLs gleichzeitig an sie übergeben, wie in:

curl -O out1.txt http://exmple.com/1 -O out2.txt http://exmple.com/2

wie unter /server/199434/how-do-i-make-curl-use-keepalive-from-the-command-line erwähnt

Vielleicht würde die Kombination beider Methoden die besten Ergebnisse liefern? Aber ich stelle mir vor, dass Parallelisierung wichtiger ist, als die Verbindung aufrechtzuerhalten.

Siehe auch: Paralleler Download mit dem Befehlszeilenprogramm Curl


7

So mache ich das auf einem Mac (OSX), aber auf anderen Systemen sollte es genauso gut funktionieren:

Was Sie brauchen, ist eine Textdatei, die Ihre Links für Curl enthält

wie so:

    http://www.site1.com/subdirectory/file1-[01-15].jpg
    http://www.site1.com/subdirectory/file2-[01-15].jpg
    .
    .
    http://www.site1.com/subdirectory/file3287-[01-15].jpg

In diesem hypothetischen Fall hat die Textdatei 3287 Zeilen und jede Zeile codiert 15 Bilder.

Angenommen, wir speichern diese Links in einer Textdatei mit dem Namen testcurl.txt auf der obersten Ebene (/) unserer Festplatte.

Jetzt müssen wir in das Terminal gehen und den folgenden Befehl in die Bash-Shell eingeben:

    for i in "`cat /testcurl.txt`" ; do curl -O "$i" ; done

Stellen Sie sicher, dass Sie Back Ticks (`) verwenden. Stellen Sie außerdem sicher, dass das Flag (-O) ein großes O und KEINE Null ist

Mit dem Flag -O wird der ursprüngliche Dateiname übernommen

Viel Spaß beim Herunterladen!


Sie sollten Ihre Variablenreferenzen angeben. Was ist, wenn jemand eine Datei mit einem Sonderzeichen in Ihre Textdatei gepflanzt hat? Fügen Sie eine Zeile hinzu echo ";sudo rm -rf ~/" >> testcurl.txtund sehen Sie, was passiert.
Ghoti

4
^ Wenn Sie es nicht wissen, tun Sie dies nicht.
Rick Hanlon II

2
Dies ist eine schreckliche Lösung; Es wird nicht nur für jeden Download ein separater Prozess erstellt, sondern es muss auch jedes Mal die TCP-Verbindung wiederhergestellt werden, was selbst in Netzwerken mit mittlerer Latenz viel Zeit verschwendet.
cnst

4

Wie andere zu Recht erwähnt haben:

-cat urls.txt | xargs -0 curl -O
+cat urls.txt | xargs -n1 curl -O

Dieses Paradigma ist jedoch eine sehr schlechte Idee, insbesondere wenn alle Ihre URLs vom selben Server stammen. Sie werden nicht nur eine weitere Curl-Instanz erzeugen, sondern auch für jede Anforderung eine neue TCP-Verbindung herstellen ist sehr ineffizient, und noch mehr mit dem mittlerweile allgegenwärtigen https.

Bitte verwenden Sie stattdessen Folgendes:

-cat urls.txt | xargs -n1 curl -O
+cat urls.txt | wget -i/dev/fd/0

Oder noch einfacher:

-cat urls.txt | wget -i/dev/fd/0
+wget -i/dev/fd/0 < urls.txt

Noch am einfachsten:

-wget -i/dev/fd/0 < urls.txt
+wget -iurls.txt

2
Im OP ging es speziell darum, wie man dies mit Locken macht. Möglicherweise ist dies für die Verwendung auf einem System vorgesehen, auf dem Curl bereits installiert ist, Wget jedoch nicht, z. B. OSX. Sie müssen sich auch nicht auf devfs verlassen, sondern können auch -i-auf stdin verweisen. Dh: wget -i- < urls.txtWenn Sie curlmehrere URLs gleichzeitig anfordern möchten , ohne dass ein Respawn erforderlich ist, können Sie diese jederzeit einfach in die Befehlszeile einfügen. xargs curl < urls.txttut dies unter Verwendung von HTTP / 1.1. Die Anzahl der URLs ist durch die Befehlszeilenlänge begrenzt, die xargs verarbeiten kann. Finden Sie diese Grenze mit heraus getconf ARG_MAX.
Ghoti
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.