Проверьте, существует ли удаленный файл в bash
я загружаю файлы с помощью этого скрипта:
parallel --progress -j16 -a ./temp/img-url.txt 'wget -nc -q -P ./images/ {}; wget -nc -q -P ./images/ {.}_{001..005}.jpg'
можно ли не загружать файлы, просто проверить их на удаленной стороне и если существует, создайте пустой файл вместо скачивания?
что-то типа:
if wget --spider $url 2>/dev/null; then
#touch img.file
fi
должно работать, но я не знаю, как объединить этот код с GNU Parallel.
Edit:
на основе ответа Ole я написал этот фрагмент кода:
#!/bin/bash
do_url() {
url=""
wget -q -nc --method HEAD "$url" && touch ./images/${url##*/}
#get filename from $url
url2=${url##*/}
wget -q -nc --method HEAD ${url%.jpg}_{001..005}.jpg && touch ./images/${url2%.jpg}_{001..005}.jpg
}
export -f do_url
parallel --progress -a urls.txt do_url {}
он работает, но он терпит неудачу для несколько файлов. Я не могу найти последовательность, почему она работает для некоторых файлов, почему она терпит неудачу для других. Может, там есть что-то с последним именем. Второй wget пытается получить доступ к url-адресу currect, но команда touch после этого просто не создает желаемый файл. Сначала wget всегда (правильно) загружает основное изображение без _001.формат JPG, _002.формат jpg.
пример url-адреса.txt:
http://host.com/092401.jpg (работает правильно, _001.формат jpg.._005.архив jpg загруженный) http://host.com/HT11019.jpg (не работает, загружается только основное изображение)
5 ответов
это довольно трудно понять, что это вы действительно хотите достичь. Позвольте мне перефразировать ваш вопрос.
Я
urls.txt
содержит:http://example.com/dira/foo.jpg http://example.com/dira/bar.jpg http://example.com/dirb/foo.jpg http://example.com/dirb/baz.jpg http://example.org/dira/foo.jpg
On эти URL-адреса:
http://example.com/dira/foo.jpg http://example.com/dira/foo_001.jpg http://example.com/dira/foo_003.jpg http://example.com/dira/foo_005.jpg http://example.com/dira/bar_000.jpg http://example.com/dira/bar_002.jpg http://example.com/dira/bar_004.jpg http://example.com/dira/fubar.jpg http://example.com/dirb/foo.jpg http://example.com/dirb/baz.jpg http://example.com/dirb/baz_001.jpg http://example.com/dirb/baz_005.jpg
On эти URL-адреса:
http://example.org/dira/foo_001.jpg
дано
urls.txt
Я хочу создать комбинации с _001.формат jpg.. _005.jpg в дополнение к исходному URL. Например:http://example.com/dira/foo.jpg
будет:
http://example.com/dira/foo.jpg http://example.com/dira/foo_001.jpg http://example.com/dira/foo_002.jpg http://example.com/dira/foo_003.jpg http://example.com/dira/foo_004.jpg http://example.com/dira/foo_005.jpg
затем я хочу проверить, существуют ли эти URL-адреса без загрузки файла. Поскольку есть много URL-адресов, я хочу сделать это параллельно.
если URL существует, я хочу создать пустой файл.
(Версия 1): я хочу, чтобы пустой файл был создан в аналогичной структуре каталогов в dir
images
. Это необходимо, потому что некоторые из изображений имеют одно и то же имя, но в разных dirs.Итак, файлы должно быть:
images/http:/example.com/dira/foo.jpg images/http:/example.com/dira/foo_001.jpg images/http:/example.com/dira/foo_003.jpg images/http:/example.com/dira/foo_005.jpg images/http:/example.com/dira/bar_000.jpg images/http:/example.com/dira/bar_002.jpg images/http:/example.com/dira/bar_004.jpg images/http:/example.com/dirb/foo.jpg images/http:/example.com/dirb/baz.jpg images/http:/example.com/dirb/baz_001.jpg images/http:/example.com/dirb/baz_005.jpg images/http:/example.org/dira/foo_001.jpg
(Версия 2): я хочу, чтобы пустой файл был создан в dir
images
. Это можно сделать, потому что все изображения имеют уникальные имена.таким образом, созданные файлы должны быть:
images/foo.jpg images/foo_001.jpg images/foo_003.jpg images/foo_005.jpg images/bar_000.jpg images/bar_002.jpg images/bar_004.jpg images/baz.jpg images/baz_001.jpg images/baz_005.jpg
(версия 3): я хочу, чтобы пустой файл был создан в dir
images
назвал имя изurls.txt
. Это можно сделать, потому что только один из _001.формат jpg.. _005.jpg существует.images/foo.jpg images/bar.jpg images/baz.jpg
#!/bin/bash
do_url() {
url=""
# Version 1:
# If you want to keep the folder structure from the server (similar to wget -m):
wget -q --method HEAD "$url" && mkdir -p images/"" && touch images/"$url"
# Version 2:
# If all the images have unique names and you want all images in a single dir
wget -q --method HEAD "$url" && touch images/""
# Version 3:
# If all the images have unique names when _###.jpg is removed and you want all images in a single dir
wget -q --method HEAD "$url" && touch images/""
}
export -f do_url
parallel do_url {1.}{2} {1//} {1/.}{2} {1/} :::: urls.txt ::: .jpg _{001..005}.jpg
GNU Parallel принимает несколько МС на работу. Когда ваши задания так коротки, накладные расходы повлияют на сроки. Если ни одно из ваших ядер процессора не работает на 100%, вы можете запускать больше заданий параллельно:
parallel -j0 do_url {1.}{2} {1//} {1/.}{2} {1/} :::: urls.txt ::: .jpg _{001..005}.jpg
вы также можете "развернуть" цикл. Это позволит сэкономить 5 накладных расходов на URL:
do_url() {
url=""
# Version 2:
# If all the images have unique names and you want all images in a single dir
wget -q --method HEAD "$url".jpg && touch images/"$url".jpg
wget -q --method HEAD "$url"_001.jpg && touch images/"$url"_001.jpg
wget -q --method HEAD "$url"_002.jpg && touch images/"$url"_002.jpg
wget -q --method HEAD "$url"_003.jpg && touch images/"$url"_003.jpg
wget -q --method HEAD "$url"_004.jpg && touch images/"$url"_004.jpg
wget -q --method HEAD "$url"_005.jpg && touch images/"$url"_005.jpg
}
export -f do_url
parallel -j0 do_url {.} :::: urls.txt
наконец, вы можете запустить более 250 заданий: https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Running-more-than-250-jobs-workaround
вы можете использовать curl
вместо этого, чтобы проверить, есть ли URL-адреса, которые вы анализируете, без загрузки какого-либо файла как такового:
if curl --head --fail --silent "$url" >/dev/null; then
touch .images/"${url##*/}"
fi
объяснение:
-
--fail
сделает статус выхода ненулевым при неудачном запросе. -
--head
будет избегать загрузки содержимого файла -
--silent
будет избегать состояния или ошибок от испускания самой проверки.
чтобы решить проблему "зацикливания", вы можете do:
urls=( "${url%.jpg}"_{001..005}.jpg )
for url in "${urls[@]}"; do
if curl --head --silent --fail "$url" > /dev/null; then
touch .images/${url##*/}
fi
done
из того, что я вижу, ваш вопрос на самом деле не о том, как использовать wget
чтобы проверить наличие файла, а скорее о том, как выполнить правильный цикл в скрипте оболочки.
вот простое решение для этого:
urls=( "${url%.jpg}"_{001..005}.jpg )
for url in "${urls[@]}"; do
if wget -q --method=HEAD "$url"; then
touch .images/${url##*/}
fi
done
что это делает, так это то, что он вызывает Wget с . С HEAD
запрос, сервер просто сообщит, существует ли файл или нет, без возврата каких-либо данных.
конечно, с большими данными установить это довольно неэффективно. Вы создаете новое соединение с сервером для каждого файла, который вы пытаетесь. Вместо этого, как было предложено в другом ответе, вы можете использовать GNU Wget2. С помощью wget2 вы можете проверить все это параллельно и использовать новый найти список всех файлов и конкретный код возврата, что сервер. Например:
$ wget2 --spider --progress=none -q --stats-site example.com/{,1,2,3}
Site Statistics:
http://example.com:
Status No. of docs
404 3
http://example.com/3 0 bytes (identity) : 0 bytes (decompressed), 238ms (transfer) : 238ms (response)
http://example.com/1 0 bytes (gzip) : 0 bytes (decompressed), 241ms (transfer) : 241ms (response)
http://example.com/2 0 bytes (identity) : 0 bytes (decompressed), 238ms (transfer) : 238ms (response)
200 1
http://example.com/ 0 bytes (identity) : 0 bytes (decompressed), 231ms (transfer) : 231ms (response)
вы даже можете получить эти данные, напечатанные в виде CSV или JSON для облегчения синтаксического анализа
просто цикл над именами?
for uname in ${url%.jpg}_{001..005}.jpg
do
if wget --spider $uname 2>/dev/null; then
touch ./images/${uname##*/}
fi
done
вы можете отправить команду через ssh, чтобы узнать, существует ли удаленный файл, и cat, если это так:
ssh your_host 'test -e "somefile" && cat "somefile"' > somefile
также можно попробовать scp, который поддерживает выражения glob и рекурсию.