Prześlij wyjście cat do cURL, aby pobrać listę plików

84

Mam listę adresów URL w pliku o nazwie urls.txt. Każda linia zawiera 1 adres URL. Chcę pobrać wszystkie pliki naraz, używając cURL. Wydaje się, że nie mogę zejść z właściwą linijką.

Próbowałem:

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

Ale to daje mi tylko ostatni plik na liście.

Zięba
źródło
11
for i in $(cat urls.txt) ; do curl -O $i ; done
bkconrad
1
Dzięki, @bkconrad. Miałem jednak problemy z nowymi trfor i in $(cat urls.txt) ; do curl -O $(echo $i | tr '\r' ' ') ; done
liniami

Odpowiedzi:

138

To działa dla mnie:

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

Jestem we FreeBSD. Twoje xargs mogą działać inaczej.

Zauważ, że działa to sekwencyjnie curl, które możesz uznać za niepotrzebnie ciężkie. Jeśli chcesz zaoszczędzić trochę tego narzutu, poniższe mogą działać w bashu:

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

Spowoduje to zapisanie listy adresów URL w tablicy, a następnie rozszerzenie tablicy z opcjami, curlaby spowodować pobranie celów. curlKomenda może trwać wiele adresów URL i pobrać wszystkie z nich, recykling istniejącego połączenia (HTTP / 1.1), ale potrzebuje -Oopcji przed każdym z nich, aby pobrać i zapisać każdy cel. Zwróć uwagę, że znaki w niektórych adresach URL] mogą wymagać zmiany znaczenia, aby uniknąć interakcji z powłoką.

Lub jeśli używasz powłoki POSIX zamiast bash:

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

Zależy to od printfzachowania polegającego na powtarzaniu wzorca formatu w celu wyczerpania listy argumentów danych; nie wszystkie samodzielne komputery printfto zrobią.

Zwróć uwagę, że ta metoda inna niż xargs może również wpływać na ograniczenia systemu w przypadku bardzo dużych list adresów URL. Badania ARG_MAX i MAX_ARG_STRLEN jeśli jest to problemem.

ghoti
źródło
Wydaje się, że to działa, ale daje mi tylko 125-bajtowy plik HTML zawierający nazwę pliku, a nie rzeczywistą zawartość pliku.
Finch
1
O, rozumiem. W -Lgrę wchodziło przekierowanie, więc musiałem dodać opcję do curl.
Finch
4
Dzięki za podpowiedź! To działa na moim Macu, ale wolę wersję pipeline cat urls.txt | xargs -n 1 curl -O;-)
orzechow
@Pio, w porządku, wszystko działa, ale dla przyjemności czytania, unix.stackexchange.com/questions/16279/ ...
ghoti
To działało świetnie !. Jednak użyłem tego w git bash \rw systemie Windows i nie podobały mi się znaki w pliku tekstowym.
James McDonnell
34

Bardzo proste rozwiązanie byłoby następujące: Jeśli masz plik „file.txt” taki jak

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

Następnie możesz użyć curl i po prostu to zrobić

curl -K file.txt

A curl będzie wywoływać wszystkie adresy URL zawarte w pliku file.txt!

Więc jeśli masz kontrolę nad formatem pliku wejściowego, być może jest to najprostsze rozwiązanie dla Ciebie!

Sztylet
źródło
1
Czy to będzie używać podtrzymywania aktywności HTTP?
William Entriken
@FullDecent Ponownie wykorzystuje połączenie w ten sposób
Allan Deamon
14

Lub możesz po prostu zrobić to:

cat urls.txt | xargs curl -O

Tego -Iparametru potrzebujesz tylko wtedy, gdy chcesz wstawić wyjście cat w środku polecenia.

user1101791
źródło
1
Nie jestem pewien, dlaczego głosowano za odrzuceniem, ale dla mnie działa idealnie, ale zamiast zwykłego pliku tekstowego do wejścia miałem wyjście grep.
okradnij
1
Prawdopodobnie przegłosowano, ponieważ jest zły. -oRozwiązaniem dla zwinięcie określa plik wyjściowy jako argument. Zalecane są inne odpowiedzi -O, które nakazują programowi curl określenie lokalnej nazwy na podstawie zdalnej nazwy pliku.
ghoti
8

xargs -P 10 | curl

GNU xargs -Pmoże curlrównolegle uruchamiać wiele procesów. Np. Do uruchamiania 10procesów:

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

Spowoduje to 10-krotne przyspieszenie pobierania, jeśli maksymalna prędkość pobierania nie zostanie osiągnięta i jeśli serwer nie ogranicza adresów IP, co jest najczęstszym scenariuszem.

Po prostu nie ustawiaj -P zbyt wysoko, bo twoja pamięć RAM może być przeciążona.

GNU parallelmoże osiągnąć podobne rezultaty.

Wadą tych metod jest to, że nie używają one jednego połączenia dla wszystkich plików, co curldzieje się, jeśli przekażesz do niego wiele adresów URL jednocześnie, jak w:

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

jak wspomniano na /server/199434/how-do-i-make-curl-use-keepalive-from-the-command-line

Może połączenie obu metod dałoby najlepsze rezultaty? Ale wyobrażam sobie, że równoległość jest ważniejsza niż utrzymanie połączenia.

Zobacz też: Pobieranie równoległe za pomocą narzędzia wiersza poleceń Curl

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
7

Oto jak to robię na Macu (OSX), ale powinno działać równie dobrze na innych systemach:

Potrzebujesz pliku tekstowego zawierającego linki do curl

tak jak:

    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

W tym hipotetycznym przypadku plik tekstowy ma 3287 linii, a każda linia koduje 15 obrazów.

Powiedzmy, że zapisujemy te linki w pliku tekstowym o nazwie testcurl.txt na najwyższym poziomie (/) naszego dysku twardego.

Teraz musimy wejść do terminala i wprowadzić następujące polecenie w powłoce bash:

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

Upewnij się, że używasz back ticków (`) Upewnij się także, że flaga (-O) jest wielką literą O a NIE zerem

z flagą -O zostanie przyjęta oryginalna nazwa pliku

Miłego pobierania!

Stefana Gruenwalda
źródło
Powinieneś cytować odniesienia do zmiennych. Co by się stało, gdyby ktoś umieścił plik ze specjalnym znakiem w twoim pliku tekstowym? Dodaj linię echo ";sudo rm -rf ~/" >> testcurl.txti zobacz, co się stanie.
ghoti
4
^ Jeśli nie wiesz, nie rób tego.
Rick Hanlon II
2
To okropne rozwiązanie; nie tylko generuje osobny proces dla każdego pobierania, ale także musi za każdym razem ponownie ustanawiać połączenie TCP, marnując dużo czasu nawet na sieciach o średnim opóźnieniu.
cnst
4

Jak słusznie wspomnieli inni:

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

Jednak ten paradygmat jest bardzo złym pomysłem, zwłaszcza jeśli wszystkie adresy URL pochodzą z tego samego serwera - nie tylko utworzysz kolejną instancję curl, ale także utworzysz nowe połączenie TCP dla każdego żądania, które jest wysoce nieefektywny, a tym bardziej w przypadku wszechobecnego HTTPS.

Użyj tego zamiast tego:

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

Lub jeszcze prościej:

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

Najprostsze jeszcze:

-wget -i/dev/fd/0 < urls.txt
+wget -iurls.txt
cnst
źródło
2
Program operacyjny dotyczył konkretnie tego, jak to zrobić za pomocą curl. Być może jest to do użytku w systemie, w którym curl jest już zainstalowany, ale wget nie, na przykład OSX. Ponadto nie ma potrzeby polegania na devfs, możesz również użyć -i-w odniesieniu do stdin. To znaczy: wget -i- < urls.txtNa koniec, jeśli chcesz curlzażądać wielu adresów URL na raz, bez konieczności odradzania się, zawsze możesz po prostu umieścić je w wierszu poleceń. xargs curl < urls.txtrobi to, używając protokołu HTTP / 1.1. Liczba adresów URL jest ograniczona długością wiersza poleceń, które xargs może przetworzyć. Dowiedz się tego limitu z getconf ARG_MAX.
ghoti