Проверьте, существует ли удаленный файл в 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.
Редактировать:
Основываясь на ответе Оле, я написал этот фрагмент кода:
#!/bin/bash
do_url() {
url="$1"
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, но после этого сенсорная команда просто не создает нужный файл. Сначала wget всегда (правильно) загружает основное изображение без _001.jpg, _002.jpg.
Пример urls.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
На
example.com
эти 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
На
example.org
эти 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): я хочу создать пустой файл в аналогичной структуре каталогов в директории
images
, Это необходимо, потому что некоторые изображения имеют одно и то же имя, но в разных папках.Итак, созданные файлы должны быть:
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): я хочу пустой файл, созданный в директории
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): я хочу пустой файл, созданный в директории
images
назвал имя изurls.txt
, Это можно сделать, потому что существует только один из _001.jpg .. _005.jpg.images/foo.jpg images/bar.jpg images/baz.jpg
#!/bin/bash
do_url() {
url="$1"
# 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/"$2" && 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/"$3"
# 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/"$4"
}
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="$1"
# 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
Вы можете использовать curl
вместо этого, чтобы проверить, существуют ли URL, которые вы анализируете, без загрузки какого-либо файла как такового:
if curl --head --fail --silent "$url" >/dev/null; then
touch .images/"${url##*/}"
fi
Объяснение:
--fail
сделает состояние выхода ненулевым при неудачном запросе.--head
будет избегать загрузки содержимого файла--silent
предотвратит выдачу статуса или ошибок самой проверкой.
Чтобы решить проблему "зацикливания", вы можете сделать:
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 с --method=HEAD
вариант. С HEAD
запрос, сервер просто сообщит, существует ли файл или нет, без возврата каких-либо данных.
Конечно, с большим набором данных это довольно неэффективно. Вы создаете новое соединение с сервером для каждого файла, который вы пытаетесь. Вместо этого, как предлагается в другом ответе, вы можете использовать GNU Wget2. С wget2 вы можете протестировать все это параллельно и использовать новые --stats-server
возможность найти список всех файлов и конкретный код возврата, предоставленный сервером. Например:
$ 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, чтобы увидеть, существует ли удаленный файл, и отследить его, если это так:
ssh your_host 'test -e "somefile" && cat "somefile"' > somefile
Можно также попробовать scp, который поддерживает выражения glob и рекурсию.