Проверьте, существует ли удаленный файл в 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 и рекурсию.