Проверьте, существует ли удаленный файл в bash

Я загружаю файлы с помощью этого script:

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="$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 пытается получить доступ к currect url, но после этого команда touch просто не создает файл с запросом. Сначала wget всегда (правильно) загружает основное изображение без _001.jpg, _002.jpg.

Пример urls.txt:

http://host.com/092401.jpg (работает правильно, загружено _001.jpg.._ 005.jpg) http://host.com/HT11019.jpg (не работает, загружается только основное изображение)

Ответ 1

Трудно понять, чего именно вы хотите достичь. Позвольте мне попытаться перефразировать ваш вопрос.

У меня есть 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#EXAMPLE:-Running-more-than-250-jobs-workaround

Ответ 2

Вместо этого вы можете использовать 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

Ответ 3

Из того, что я вижу, ваш вопрос заключается не в том, как использовать wget для проверки существования файла, а скорее о том, как выполнить правильный цикл в оболочке script.

Вот простое решение для этого:

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 для упрощения анализа

Ответ 4

Просто перебирайте имена?

for uname in ${url%.jpg}_{001..005}.jpg
do
  if wget --spider $uname 2>/dev/null; then
    touch ./images/${uname##*/}
  fi
done

Ответ 5

Вы можете отправить команду через ssh, чтобы узнать, существует ли удаленный файл и котировать его, если он:

ssh your_host 'test -e "somefile" && cat "somefile"' > somefile

Также можно попробовать scp, который поддерживает выражения glob и рекурсию.