chỉ tải xuống tệp qua http nếu thay đổi kể từ lần cập nhật trước


20

Tôi cần tải xuống một tệp từ máy chủ HTTP, nhưng chỉ khi nó thay đổi kể từ lần cuối tôi tải xuống (ví dụ: qua If-Modified-Sincetiêu đề). Tôi cũng cần sử dụng tên tùy chỉnh cho tệp trên đĩa của mình.

Tôi có thể sử dụng công cụ nào cho tác vụ này trên linux?


wget -Nkhông thể được sử dụng bởi vì -Nkhông thể được sử dụng với -O.


Tại sao không tải tập tin và sau đó đổi tên nó?
Julian Knight

.. bởi vì công cụ vẫn cần có thể kiểm tra xem tài nguyên HTTP có thay đổi kể từ lần tải xuống cuối cùng không? Điều này sẽ khó nếu tệp đã được đổi tên và do đó không còn tồn tại ở nơi mà công cụ mong đợi.
cweiske

Xin lỗi, tôi vội vàng bình luận, xem câu trả lời của tôi.
Julian Knight

Câu trả lời:


26

Cân nhắc sử dụng curlthay vì wget:

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

man curl nói:

-z/ --time-cond <biểu thức ngày>

(HTTP / FTP) Yêu cầu một tệp đã được sửa đổi muộn hơn thời gian và ngày đã cho hoặc một tệp đã được sửa đổi trước thời điểm đó. Biểu thức ngày có thể là tất cả các loại chuỗi ngày hoặc nếu nó không khớp với bất kỳ chuỗi nội bộ nào, nó sẽ cố gắng lấy thời gian từ một tên tệp đã cho.

Nếu $filekhông nhất thiết tồn tại trước, bạn sẽ cần sử dụng -zcờ có điều kiện, sử dụng test -e "$file":

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

(Lưu ý rằng chúng tôi không trích dẫn việc mở rộng $zflagở đây, vì chúng tôi muốn nó trải qua quá trình phân tách thành 0 hoặc 2 mã thông báo).

Nếu hệ vỏ của bạn hỗ trợ các mảng (ví dụ Bash), thì chúng tôi có phiên bản an toàn hơn và sạch hơn:

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

7

Công tắc wget -Nchỉ nhận được tệp nếu nó đã thay đổi, vì vậy cách tiếp cận có thể là sử dụng công -Ntắc đơn giản sẽ nhận tệp nếu cần nhưng để lại tên sai. Sau đó tạo một liên kết cứng bằng cách sử dụng ln -Plệnh để liên kết nó với một "tệp" với tên chính xác. Tệp được liên kết có siêu dữ liệu giống như bản gốc.

Hạn chế duy nhất là bạn không thể có các liên kết cứng trên các ranh giới hệ thống tệp.


Đối với nhiều mục đích, một liên kết tượng trưng có thể là đầy đủ - trừ khi danh tính inode thực sự quan trọng đối với người hỏi.
Toby Speight

1
wget là công cụ tốt hơn cho công việc này. Nó kiểm tra dấu thời gian VÀ kích thước tệp, mà curl (7.38.0) không. Ngoài ra, wget chấm dứt với số 0 trên 4xx / 5xx, trong khi curl không thực sự quan tâm đến mã máy chủ theo mặc định.
schieferstapel

4

Kịch bản Python 3.5+ để gói lệnh 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 (),
))

Điều này thật tuyệt! TIL chain:)
John Oxley

1

Một cách tiếp cận tương tự với " kiểm tra ngày " (với "curl --time-cond"), sẽ là tải xuống theo so sánh kích thước tệp, tức là Chỉ tải xuống nếu tệp cục bộ có kích thước khác với tệp từ xa .

Ví dụ, nó rất hữu ích, khi quá trình tải xuống thất bại ở giữa và do đó, tệp tải xuống cục bộ có ngày mới hơn tệp từ xa, nhưng thực sự nó bị hỏng và cần phải tải xuống lại:

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

Tùy chọn "curl -z / --time-cond" (được đề xuất trong câu trả lời khác) sẽ không tải xuống tệp từ xa trong trường hợp này (vì tệp cục bộ có ngày mới hơn), nhưng tập lệnh " kiểm tra kích thước " này sẽ!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.