Datei nur über http herunterladen, wenn seit dem letzten Update geändert

20

Ich muss eine Datei von einem HTTP-Server herunterladen, aber nur, wenn sie sich seit dem letzten Herunterladen geändert hat (z. B. über den If-Modified-SinceHeader). Ich muss auch einen benutzerdefinierten Namen für die Datei auf meiner Festplatte verwenden.

Welches Tool kann ich für diese Aufgabe unter Linux verwenden?


wget -Nkann nicht verwendet werden, da -Nnicht mit verwendet werden kann -O.

Cweiske
quelle
Warum nicht die Datei herunterladen und dann umbenennen?
Julian Knight
.. weil das Tool noch prüfen muss, ob sich die HTTP-Ressource seit dem letzten Download geändert hat? Dies ist schwierig, wenn die Datei umbenannt wurde und daher nicht mehr an der Stelle vorhanden ist, an der das Tool dies erwartet.
Cweiske
Entschuldigung, ich habe diesen Kommentar überstürzt, siehe meine Antwort.
Julian Knight

Antworten:

26

Erwägen Sie die Verwendung curlanstelle von wget:

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

man curl sagt:

-z/ --time-cond <Datumsausdruck>

(HTTP / FTP) Fordern Sie eine Datei an, die nach dem angegebenen Zeitpunkt und Datum geändert wurde, oder eine Datei, die vor diesem Zeitpunkt geändert wurde. Der Datumsausdruck kann aus allen möglichen Datumszeichenfolgen bestehen. Wenn er nicht mit internen Zeichenfolgen übereinstimmt, wird stattdessen versucht, die Uhrzeit von einem bestimmten Dateinamen abzurufen.

Wenn es $filedas nicht unbedingt gibt, müssen Sie die Verwendung des -zFlags unter folgenden Bedingungen festlegen test -e "$file":

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

(Beachten Sie, dass wir die Erweiterung von $zflaghier nicht zitieren , da wir möchten, dass sie in 0 oder 2 Token aufgeteilt wird.)

Wenn Ihre Shell Arrays (zB Bash) unterstützt, haben wir eine sicherere und sauberere Version:

if test -e "$file"
then zflag=(-z "$file")
else zflag=()
fi
curl -o "$file" "${zflag[@]}" "$uri"
Toby Speight
quelle
7

Der wget-Schalter -Nruft die Datei nur ab, wenn sie geändert wurde. Ein möglicher Ansatz besteht darin, den einfachen -NSchalter zu verwenden, der die Datei abruft, wenn dies erforderlich ist, sie jedoch mit dem falschen Namen belässt. Erstellen Sie dann eine feste Verknüpfung, indem Sie den ln -PBefehl verwenden, um sie mit einer "Datei" mit dem richtigen Namen zu verknüpfen. Die verknüpfte Datei enthält dieselben Metadaten wie das Original.

Die einzige Einschränkung besteht darin, dass Sie keine festen Verknüpfungen über Dateisystemgrenzen hinweg haben können.

Julian Knight
quelle
Für viele Zwecke kann eine symbolische Verknüpfung ausreichend sein - es sei denn, die Identität des Inodes ist tatsächlich für den Fragesteller von Bedeutung.
Toby Speight
1
wget ist das bessere Werkzeug für diesen Job. Es prüft den Zeitstempel UND die Dateigröße, was Curl (7.38.0) nicht tut. Außerdem endet wget bei 4xx / 5xx mit einem Wert ungleich 0, wohingegen sich curl standardmäßig nicht wirklich um Server-Codes kümmert.
schieferstapel
4

Python 3.5+-Skript zum Umschließen des Befehls 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
quelle
Das ist fantastisch! Bis chain:)
John Oxley
1

Ein ähnlicher Ansatz zur " Datumsprüfung " (mit "curl - time-cond") wäre das Herunterladen gemäß dem Dateigrößenvergleich, dh Herunterladen nur, wenn die lokale Datei eine andere Größe als die entfernte Datei hat .

Dies ist beispielsweise hilfreich, wenn der Download-Vorgang in der Mitte fehlgeschlagen ist und die lokal heruntergeladene Datei ein neueres Datum als die Remote-Datei erhält, aber tatsächlich beschädigt ist und ein erneuter Download erforderlich ist:

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

Die „curl -z / --time-cond“ Option (die in einer anderen Antwort vorgeschlagen wurde) nicht die Remote - Datei in diesem Fall herunterladen (Ursache der lokale Datei ein neueres Datum hat), aber dieses „ Größe Check “ Skript wird!

Noam Manos
quelle