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

20

Мне нужно скачать файл с HTTP-сервера, но только если он изменился с момента последней загрузки (например, через If-Modified-Sinceзаголовок). Мне также нужно использовать произвольное имя для файла на моем диске.

Какой инструмент я могу использовать для этой задачи в Linux?


wget -Nне может быть использован, потому что -Nне может быть использован с -O.

cweiske
источник
Почему бы не скачать файл, а затем переименовать его?
Джулиан Найт
.. потому что инструмент все еще должен иметь возможность проверить, изменился ли ресурс HTTP с момента последней загрузки? Это будет сложно, если файл был переименован и, следовательно, больше не существует в том месте, где его ожидает инструмент.
cweiske
Извините, я срочно отправил этот комментарий, см. Мой ответ.
Джулиан Найт

Ответы:

26

Попробуйте использовать curlвместо wget:

curl -o "$file" -z "$file" "$uri"

man curl говорит:

-z/ --time-cond <выражение даты>

(HTTP / FTP) Запросить файл, который был изменен позднее, чем указанное время и дата, или файл, который был изменен до этого времени. Выражение даты может быть всевозможными строками даты или, если оно не совпадает ни с какими внутренними, вместо этого оно пытается получить время из заданного имени файла.

Если $fileэто не обязательно существует, вам нужно использовать -zфлаг условно, используя test -e "$file":

if test -e "$file"
then zflag="-z '$file'"
else zflag=
fi
curl -o "$file" $zflag "$uri"

(Обратите внимание, что мы не указываем здесь расширение $zflag, поскольку мы хотим, чтобы оно подвергалось расщеплению до 0 или 2 токенов).

Если ваша оболочка поддерживает массивы (например, Bash), у нас есть более безопасная и чистая версия:

if test -e "$file"
then zflag=(-z "$file")
else zflag=()
fi
curl -o "$file" "${zflag[@]}" "$uri"
Тоби Спейт
источник
7

Переключатель wget -Nполучает файл только в том случае, если он изменился, поэтому возможный подход заключается в использовании простого -Nпереключателя, который получит файл, если он потребуется, но оставит его с неправильным именем. Затем создайте жесткую ссылку, используя ln -Pкоманду, чтобы связать ее с «файлом» с правильным именем. Связанный файл имеет те же метаданные, что и оригинал.

Единственным ограничением является то, что вы не можете иметь жесткие ссылки через границы файловой системы.

Джулиан Найт
источник
Для многих целей символическая ссылка может быть адекватной - если только идентификация inode не имеет значения для спрашивающего.
Тоби Спейт
1
Wget - лучший инструмент для этой работы. Он проверяет временную метку И размер файла, чего нет в curl (7.38.0). Кроме того, wget завершается с ненулевым значением в 4xx / 5xx, тогда как curl на самом деле не заботится о серверных кодах по умолчанию.
schieferstapel
4

Скрипт Python 3.5+ для переноса команды curl:

import argparse
import pathlib

from subprocess import run
from itertools import chain

parser = argparse.ArgumentParser()
parser.add_argument('url')
parser.add_argument('filename', type=pathlib.Path)
args = parser.parse_args()

run(chain(
    ('curl', '-s', args.url),
    ('-o', str(args.filename)),
    ('-z', str(args.filename)) if args.filename.exists() else (),
))
Sirex
источник
Это круто! TIL chain:)
Джон Оксли,
1

Аналогичный подход к « проверке даты » (с «curl - time-cond») заключается в загрузке в соответствии со сравнением размера файла, т.е. загрузка только в том случае, если размер локального файла отличается от размера удаленного файла .

Это полезно, например, когда процесс загрузки не удался в середине , и, таким образом, локальный загруженный файл получает более новую дату, чем удаленный файл, но он фактически поврежден, и требуется повторная загрузка:

local_file_size=$([[ -f ${FILE_NAME} ]] && wc -c < ${FILE_NAME} || echo "0")
remote_file_size=$(curl -sI ${FILE_URL} | awk '/Content-Length/ { print $2 }' | tr -d '\r' )

if [[ "$local_file_size" -ne "$remote_file_size" ]]; then
    curl -o ${FILE_NAME} ${FILE_URL}
fi

Опция "curl -z / --time-cond" (которая была предложена в другом ответе) не будет загружать удаленный файл в этом случае (поскольку локальный файл имеет более новую дату), но этот скрипт " проверки размера " будет!

Ноам Манос
источник