По конвейеру вывод cat в cURL для загрузки списка файлов

84

У меня есть список URL-адресов в файле с именем urls.txt. Каждая строка содержит 1 URL. Я хочу загрузить все файлы сразу, используя cURL. Кажется, я не могу написать правильный однострочный текст.

Я старался:

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

Но это дает мне только последний файл в списке.

Зяблик
источник
11
for i in $(cat urls.txt) ; do curl -O $i ; done
bkconrad
1
Спасибо, @bkconrad. У меня были проблемы с переводом строки в Windows, я исправил это с помощью tr:for i in $(cat urls.txt) ; do curl -O $(echo $i | tr '\r' ' ') ; done
biphobe 02

Ответы:

138

Это работает для меня:

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

Я во FreeBSD. Ваши xargs могут работать по-другому.

Обратите внимание, что это запускает последовательные curls, которые вы можете рассматривать как излишне тяжелые. Если вы хотите сэкономить часть этих накладных расходов, в bash может работать следующее:

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

Это сохраняет ваш список URL-адресов в массив, а затем расширяет массив с параметрами, curlчтобы вызвать загрузку целей. Команда curlможет принимать несколько URL-адресов и извлекать их все, перезагружая существующее соединение (HTTP / 1.1), но ей нужна -Oопция перед каждым из них, чтобы загрузить и сохранить каждую цель. Обратите внимание, что символы в некоторых URL-адресах] может потребоваться экранировать, чтобы избежать взаимодействия с вашей оболочкой.

Или, если вы используете оболочку POSIX, а не bash:

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

Это зависит от printfповедения повторения шаблона формата для исчерпания списка аргументов данных; не все автономные printfs будут делать это.

Обратите внимание, что этот метод, отличный от xargs, также может не соответствовать системным ограничениям для очень больших списков URL-адресов. Исследования ARG_MAX и MAX_ARG_STRLEN , если это является проблемой.

гхоти
источник
Кажется, это работает, но он дает мне только 125-байтовый HTML-файл, содержащий имя файла, а не фактическое содержимое файла.
Finch
1
Ах я вижу. Было задействовано перенаправление, поэтому мне нужно было добавить эту -Lопцию в curl.
Finch
4
Спасибо за подсказку! Это работает на моем Mac, но я предпочитаю конвейерную версию cat urls.txt | xargs -n 1 curl -O;-)
orzechow
@Pio, достаточно справедливо, все это работает, но для вашего удовольствия чтения, unix.stackexchange.com/questions/16279/...
Ghoti
Это отлично сработало !. Однако я использовал это в git bash для Windows, и ему не нравились \rсимволы в текстовом файле.
Джеймс МакДоннелл
34

Очень простым решением будет следующее: Если у вас есть файл file.txt вроде

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

Затем вы можете использовать curl и просто сделать

curl -K file.txt

И curl вызовет все URL-адреса, содержащиеся в вашем файле file.txt!

Так что, если у вас есть контроль над форматом входного файла, возможно, это самое простое решение для вас!

Дирк
источник
1
Будет ли это использовать HTTP keep-alive?
Уильям Энтрикен,
@FullDecent Это повторно использует соединение таким образом
Аллан Димон
14

Или вы можете просто сделать это:

cat urls.txt | xargs curl -O

Вам нужно использовать -Iпараметр только тогда, когда вы хотите вставить вывод cat в середину команды.

user1101791
источник
1
не уверен, почему это отклонено, но для меня он отлично работает, но вместо простого текстового файла для ввода у меня был вывод grep.
ограбить
1
Вероятно, проголосовали против, потому что это неправильно. Параметр -ocurl указывает выходной файл в качестве аргумента. Другие ответы рекомендуют -O, что говорит curl определять локальное имя на основе удаленного имени файла.
ghoti
8

xargs -P 10 | curl

GNU xargs -Pможет запускать несколько curlпроцессов параллельно. Например, для запуска 10процессов:

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

Это ускорит загрузку в 10 раз, если ваша максимальная скорость загрузки не будет достигнута, и если сервер не регулирует IP-адреса, что является наиболее распространенным сценарием.

Просто не устанавливайте -Pслишком высокий уровень, иначе ваша оперативная память может быть перегружена.

GNU parallelможет достичь аналогичных результатов.

Обратной стороной этих методов является то, что они не используют одно соединение для всех файлов, что curlпроизойдет, если вы передадите ему несколько URL-адресов одновременно, как в:

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

как указано на /server/199434/how-do-i-make-curl-use-keepalive-from-the-command-line

Может быть, сочетание обоих методов даст лучший результат? Но я полагаю, что распараллеливание важнее, чем поддержание связи.

См. Также: Параллельная загрузка с помощью утилиты командной строки Curl

Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
7

Вот как я делаю это на Mac (OSX), но он должен работать одинаково хорошо и в других системах:

Вам нужен текстовый файл, содержащий ваши ссылки для curl.

вот так:

    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

В этом гипотетическом случае текстовый файл имеет 3287 строк, и каждая строка кодирует 15 изображений.

Допустим, мы сохраняем эти ссылки в текстовом файле с именем testcurl.txt на верхнем уровне (/) нашего жесткого диска.

Теперь нам нужно войти в терминал и ввести следующую команду в оболочке bash:

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

Убедитесь, что вы используете обратные галочки (`). Также убедитесь, что флаг (-O) - это заглавная буква O, а НЕ ноль.

с флагом -O будет использовано исходное имя файла

Удачной загрузки!

Стефан Грюнвальд
источник
Вы должны указать ссылки на переменные. Что, если кто-то подложил в ваш текстовый файл файл со специальным символом? Добавьте строку echo ";sudo rm -rf ~/" >> testcurl.txtи посмотрите, что получится.
ghoti
4
^ Если вы не знаете, не делайте этого.
Рик Хэнлон II
2
Это ужасное решение; он не только порождает отдельный процесс для каждой загрузки, но также должен каждый раз заново устанавливать TCP-соединение, тратя много времени даже в сетях со средней задержкой.
cnst
4

Как правильно отметили другие:

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

Однако эта парадигма - очень плохая идея, особенно если все ваши URL-адреса поступают с одного и того же сервера - вы не только создадите еще один экземпляр curl, но также будете устанавливать новое TCP-соединение для каждого запроса, что крайне неэффективен, и тем более с теперь повсеместным https.

Пожалуйста, используйте это вместо:

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

Или еще проще:

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

Самый простой:

-wget -i/dev/fd/0 < urls.txt
+wget -iurls.txt
cnst
источник
2
OP был конкретно о том, как это сделать с помощью curl. Возможно, это для использования в системе, где curl уже установлен, а wget нет, например OSX. Кроме того, нет необходимости зависеть от devfs, вы также можете использовать -i-для ссылки на stdin. Т.е., wget -i- < urls.txtнаконец, если вы хотите curlзапросить несколько URL-адресов одновременно, не требуя повторного появления, вы всегда можете просто поместить их в командную строку. xargs curl < urls.txtделает это, используя HTTP / 1.1. Количество URL-адресов ограничено длиной командной строки, которую может обрабатывать xargs. Узнайте этот предел с помощью getconf ARG_MAX.
ghoti