![在 'wget' 收到 404 错误后如何停止它?](https://linux22.com/image/40356/%E5%9C%A8%20'wget'%20%E6%94%B6%E5%88%B0%20404%20%E9%94%99%E8%AF%AF%E5%90%8E%E5%A6%82%E4%BD%95%E5%81%9C%E6%AD%A2%E5%AE%83%EF%BC%9F.png)
如果将大括号扩展与 一起使用wget
,则可以轻松获取按顺序编号的图像:
$ wget 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'
它获取前 10 个编号90.jpg
为99.jpg
就好的文件,但是100.jpg
然后返回一个404:找不到文件错误(我的服务器上只存储了 100 张图片)。如果您使用更大的范围,例如{00..200}
,有 100 个不存在的文件,这些不存在的文件将成为更大的“问题”,这会增加脚本的执行时间,甚至可能成为服务器的轻微负担(或至少是烦恼)。
有什么方法可以wget
在收到第一个 404 错误后停止吗? (或者更好的是,连续两个,以防由于其他原因在范围内丢失文件)答案不需要使用大括号扩展;循环也很好。
答案1
如果您对循环感到满意:
for url in 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'
do
wget "$url" || break
done
这将为扩展中的每个 URL 运行,wget
直到失败,然后break
退出循环。
如果您希望连续两次失败,情况会变得更加复杂:
for url in 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'
do
if wget "$url"
then
failed=
elif [ "$failed" ]
then
break
else
failed=yes
fi
done
&&
您可以使用和||
来缩小它一点if
,但它会变得非常难看。
我不相信wget
有任何内置的东西可以做到这一点。
答案2
您可以使用该$?
变量来获取 wget 的返回码。如果它非零,则意味着发生了错误,并且您对其进行计数直到达到阈值,然后它可能会跳出循环。
我的脑海里浮现出这样的事情
#!/bin/bash
threshold=0
for x in {90..110}; do
wget 'http://www.iqandreas.com/sample-images/100-100-color/'$x'.jpg'
wgetreturn=$?
if [[ $wgetreturn -ne 0 ]]; then
threshold=$(($threshold+$wgetreturn))
if [[ $threshold -eq 16 ]]; then
break
fi
fi
done
for 循环可以稍微清理一下,但您可以理解总体思路。
更改$threshold -eq 16
为-eq 24
意味着它将失败 3 次才会停止,但是它不会连续两次,而是如果在循环中失败两次就会失败。
16
使用和的原因24
是它是返回码的总和。当 wget 收到与来自服务器的错误相对应的响应代码时,
它会使用返回代码进行响应,因此是 2 个错误后的总数。8
16
当失败仅连续发生两次时停止可以通过在wget
成功时重置阈值来完成,即当返回码为 0 时
wget 返回代码的列表可以在这里找到 -http://www.gnu.org/software/wget/manual/html_node/Exit-Status.html
答案3
IMO,关注 的wget
退出代码/状态对于某些用例来说可能太天真,因此这里也考虑了 HTTP 状态代码以及一些细粒度的决策。
wget
提供一个-S/--server-response
标志来打印STDERR
命令的 HTTP 响应标头 - 我们可以提取该标头并对其进行操作。
#!/bin/bash
set -eu
error_max=2
error_count=0
urls=( 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg' )
for url in "${urls[@]}"; do
set +e
http_status=$( wget --server-response -c "$url" 2>&1 )
exit_status=$?
http_status=$( awk '/HTTP\//{ print $2 }' <<<"$http_status" | tail -n 1 )
if (( http_status >= 400 )); then
# Considering only HTTP Status errors
case "$http_status" in
# Define your actions for each 4XX Status Code below
410) : Gone
;;
416) : Requested Range Not Satisfiable
error_count=0 # Reset error_count in case of `wget -c`
;;
403) : Forbidden
;&
404) : Not Found
;&
*) (( error_count++ ))
;;
esac
elif (( http_status >= 300 )); then
# We're unlikely to reach here in case of 1XX, 3XX in $http_status
# but ..
exit_status=0
elif (( http_status >= 200 )); then
# 2XX in $http_status considered successful
exit_status=0
elif (( exit_status > 0 )); then
# Where wget's exit status is one of
# 1 Generic error code.
# 2 Parse error
# - when parsing command-line options, the .wgetrc or .netrc...
# 3 File I/O error.
# 4 Network failure.
# 5 SSL verification failure.
# 6 Username/password authentication failure.
# 7 Protocol errors.
(( error_count++ ))
fi
echo "$url -> http_status: $http_status, exit_status=$exit_status, error_count=$error_count" >&2
if (( error_count >= error_max )); then
echo "error_count $error_count >= $error_max, bailing out .." >&2
exit "$exit_status"
fi
done
答案4
我成功使用的是
wget 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg' 2>&1 | grep -q 'ERROR 404: Not Found'
grep -q
在其输入中查找 404 错误消息模式,并在看到它后立即终止。 wget
一旦尝试写入grep
不再读取的管道,就会收到 SIGPIPE 信号。实际上,wget
在收到第一个 404 错误后很快就会死亡。