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

Другие вопросы по тегам