Comments 48
Тоже занимаюсь написанием удобного интерфейса для wget, пишу его под web на java.
Спасибо за подсказку, сейчас попробую ее использовать.
Внес изменения в скрипт по Вашему совету. Вместо:
Вот этот код:
while [ $i -le $threads ]
do
download_thread $i &
sleep 1
i=`expr $i + 1`
done
if [ ! -e $error_list ]; then touch $error_list; fi
# По наличию записей в active.lst error.lst проверяем идет ли закачка
while [ -s $active_list ] || [ -s $error_list ]
do
sleep 1
done
Вот этот код:
while [ $i -le $threads ]
do
download_thread $i &
downloader_pid="${downloader_pid} $!"
sleep 1
i=`expr $i + 1`
done
if [ ! -e $error_list ]; then touch $error_list; fi
# Ждем окончания всех закачек
wait $downloader_pid
А почему бы не использовать aria2c? Можно будет убрать threads.
Да, есть такая замечательная утилита — aria2c (поддерживает скачивание нескольких файлов одновремено, скачивание по списку, + еще скачивание сегментами одного файла). Правда о ее существовании я узнал только после начала работы над скриптом. Поэтому, чтобы оправдать проделанную мной работу, скажу: wget входит практически во все дистрибутивы *nix (можно сказать что это стандарт). Так что для тех у кого нет возможности/желания устанавливать дополнительные программы я написал этот скрипт =)
Ну вообще то не во все, к примеру в FreeBSD по дефолту нет wget, придётся ставить из портов.
есть fetch.
Поэтому и написал: «практически». Хотя, если откровенно, то не знал что wget не входит в FreeBSD, думал, что он входит во все популярные дистрибутивы. Теперь думаю что это относится, скорее, к потомкам System V.
Формат инит-файлов никак не связан с наличием wget в дистрибутиве.
Насколько я помню: System V и BSD отличаются не только форматом инит-файлов (с этой темой не очень знаком, поэтому спорить не буду).
Но мое упоминание здесь system V в отношении wget было не очень уместно, потому что linux дистрибутивы содержат особенности реализации разных веток unix (System V и BSD в том числе). Поэтому наличие/отсутствие wget можно отнести только к особенностям конкретного дистрибутива.
Но мое упоминание здесь system V в отношении wget было не очень уместно, потому что linux дистрибутивы содержат особенности реализации разных веток unix (System V и BSD в том числе). Поэтому наличие/отсутствие wget можно отнести только к особенностям конкретного дистрибутива.
Предпологаю, что это связано с GNU.
Ух ты, еще один полезный скрипт в копилку :)
Тоже хочу поблагодарить того человека, который пригласил полезного и интересного человека на хабр :)
Тоже хочу поблагодарить того человека, который пригласил полезного и интересного человека на хабр :)
Можно вместо wget использовать axel — еще и в несколько потоков грузить умеет «из коробки»
в заголовке #!/bin/bash, а запускать советуете через sh.
а не проще сделать примерно так:
а не проще сделать примерно так:
l=`wc -l $download_list`
la=`echo "$l/$n" | bc`
split -l $la download_list down_split
for $i in `ls down_split*`; do
wget -i $i &
done
wait
ошибочка:
l=`wc -l $download_list |awk '{print $1}'` la=`echo "$l/$n" | bc` echo $la split -l $la $download_list down_split for i in `ls down_split*`; do wget -p -i $i & done wait rm down_split*
/bin/bash исправил на /bin/sh
А такой способ деления списка — тоже вариант. Просто я хотел чтобы список можно было пополнять и во время закачек. Это до конца не реализовано (если качается в несколько потоков, все кроме одного завершились, то при добавлении в список n ссылок они будут качаться одним потоком). Можно немного изменить скрипт чтобы потоки не завершались, а раз в n минут проверяли опять список. Тогда можно использовать его, например, на сервере: просто скидывать сслыки в файл (echo ... >> download.lst)и они сами будут скачиваться.
А такой способ деления списка — тоже вариант. Просто я хотел чтобы список можно было пополнять и во время закачек. Это до конца не реализовано (если качается в несколько потоков, все кроме одного завершились, то при добавлении в список n ссылок они будут качаться одним потоком). Можно немного изменить скрипт чтобы потоки не завершались, а раз в n минут проверяли опять список. Тогда можно использовать его, например, на сервере: просто скидывать сслыки в файл (echo ... >> download.lst)и они сами будут скачиваться.
А вы уверены, что у вас башизмов в коде нет, чтоб смело на /bin/sh исправлять? :-)
Честно — не уверен. Если совсем откровенно, то еще не разобрался в их отличиях :) Не судите строго, повторюсь — это мой первый опыт. Просто тестил и использовал при помощи `sh downloader ...` и все работало.
>Ух ты, еще один полезный скрипт в копилку :)
а можно глянуть что в копилке?
а можно глянуть что в копилке?
используйте mktemp для создания временных файлов.
Спасибо, добавил в скрипт использование mktemp.
Плюсы:
— можно отказаться от переменной tmp_dir.
— создается случайное имя (вместо «XX» — буквы/цифры), что исключает возможности перезаписи одного временного файла при одновременном вхождении в функцию move_line() в разных потоках.
Плюсы:
— можно отказаться от переменной tmp_dir.
— создается случайное имя (вместо «XX» — буквы/цифры), что исключает возможности перезаписи одного временного файла при одновременном вхождении в функцию move_line() в разных потоках.
— никто не сотрёт ваш /home/luser/.ssh/id_rsa симлинком из /tmp/staticfilename -> /home/…
Не совсем понял о чем речь. Я имел ввиду, что ранее использованный код:
дает вероятность (хоть и маленькую), что в двух потоках одновременно выполнится строка №3 (т.е. временный файл одного потока перезапишется данными другого потока).
1. tmp_file="${tmp_dir}/downloader.tmp"
2. echo $1 >> $3
3. cat $2 | grep -v $1 > $tmp_file
4. mv $tmp_file $2
дает вероятность (хоть и маленькую), что в двух потоках одновременно выполнится строка №3 (т.е. временный файл одного потока перезапишется данными другого потока).
Плюс к тому, возможно перед стартом программы существует "${tmp_dir}/downloader.tmp", который является символьной ссылкой на файл, принадлежащий пользователю.
Таким образом, можно уничтожить файл пользователя, т.к. tmp_dir == /tmp а туда право на запись имеют все.
Поэтому надо использовать mktemp, который создаст НОВЫЙ файл и, возможно, использовать set -o noclobber (но второе — это уже для по настоящему параноидально написанных скриптов)
Таким образом, можно уничтожить файл пользователя, т.к. tmp_dir == /tmp а туда право на запись имеют все.
Поэтому надо использовать mktemp, который создаст НОВЫЙ файл и, возможно, использовать set -o noclobber (но второе — это уже для по настоящему параноидально написанных скриптов)
Данная атака имеет какое-то правильное название, но я его точно не помню. Ключевой момент, что файл в /tmp может быть символьной ссылкой и его может создать злоумышленник.
Вообще, при написании скриптов никогда не стоит забывать, что UNIX — многопользовательская система, поэтому в kill стоит еще и UID проверять, а также по-хорошему стоит отправлять сначала TERM и только через некоторое время KILL.
:-)
Вообще, при написании скриптов никогда не стоит забывать, что UNIX — многопользовательская система, поэтому в kill стоит еще и UID проверять, а также по-хорошему стоит отправлять сначала TERM и только через некоторое время KILL.
:-)
А у меня есть свой велосипед на баше для этого дела, забросил ввиду перехода на emacs-wget
Автору большое спасибо, выполнил хорошую автоматизацию отличной программы
Вам спасибо за отзыв и остальным за конструктивную критику. Все это добавляет энтузиазма для работы над чем-нибудь полезным для общества ;)
Вот вам хороший пример, хорошей связки curl+bash Пример скрипта Я думаю будет полезно Вам в нем покапаться :)
>Для работы скрипта необходимо сделать его исполняемым и создать файл "./list/download.lst" со списком ссылок для скачивания.
Запуск:
sh downloader start [количество одновременных скачиваний]
Небольшое замечание:
Если мы собираемся запускать скрипт именно так (передавая как параметр sh), то исполняемым его делать вовсе необязательно.
Исполняемым его нужно делать для того, чтобы иметь возможность запустить непосредственно его самого:
Запуск:
sh downloader start [количество одновременных скачиваний]
Небольшое замечание:
Если мы собираемся запускать скрипт именно так (передавая как параметр sh), то исполняемым его делать вовсе необязательно.
Исполняемым его нужно делать для того, чтобы иметь возможность запустить непосредственно его самого:
$ ./downloader [number of downloads]
я дописал еще такую штучку
wget -c -o "${log_dir}/wget_thread${thread}.log" -O "${output_dir}/$(basename "$url")" $url 2>&1 | sed -u 's/.*\ \([0-9]\+%\)\ \+\([0-9.]\+\ [KMB\/s]\+\)$/\1\n# Downloading \2/' | zenity --progress --width=500 --title=«Downloading File: $(basename „$url“)»
Мне удобно, когда в GNOME вылетает окошко с прогресс-баром
wget -c -o "${log_dir}/wget_thread${thread}.log" -O "${output_dir}/$(basename "$url")" $url 2>&1 | sed -u 's/.*\ \([0-9]\+%\)\ \+\([0-9.]\+\ [KMB\/s]\+\)$/\1\n# Downloading \2/' | zenity --progress --width=500 --title=«Downloading File: $(basename „$url“)»
Мне удобно, когда в GNOME вылетает окошко с прогресс-баром
как только мои shell скрипты переваливают за 20 строк, я бросаю шелл и перехожу на более удобный инструмент.
в частности, ваш скрипт подвершен упомянутому race condition, т.к. потоки никак не синхронизируются и могут запросто перетереть и файлы списков и сами скачиваемые файлы.
в образовательных целях шелл знать не помешает, но в работе нужны другие инструменты.
если в шелл скрипте более 1 раза встретились grep и awk — скрипт пора переписывать.
в частности, ваш скрипт подвершен упомянутому race condition, т.к. потоки никак не синхронизируются и могут запросто перетереть и файлы списков и сами скачиваемые файлы.
в образовательных целях шелл знать не помешает, но в работе нужны другие инструменты.
если в шелл скрипте более 1 раза встретились grep и awk — скрипт пора переписывать.
mktemp явно ждёт ещё одного X в 20 строчке, покрайней мере mktemp (GNU coreutils) 7.4 точно не работает без.
если не прибавить к параметрам запуска wget
--user-agent=«какой вам больше нравится»
многие-многие сайты будут футболить запросы потому что банлисты
--user-agent=«какой вам больше нравится»
многие-многие сайты будут футболить запросы потому что банлисты
И вот это будет в тему
--wait=секунды --random-wait
--wait=секунды --random-wait
Sign up to leave a comment.
Расширяем возможности wget