Wget 或 bash 通过额外插入 space 来改变时间戳值
Wget or bash alters a timestamp value with an extra interposed space
在 bash 提示符下我们有:
bash> if_modified_since=`date --date="2 hours ago 5 minutes ago" +%a,\ %e\ %b\ %Y\ %H:%M:%S\ GMT`
bash> echo $ts_modified_since
Mon, 3 Aug 2015 08:45:18 GMT
请注意 Mon,
和尾随 3 Aug...
之间有一个 space,这是预期的。
但是当尝试使用值 $if_modified_since
时,在 Mon,
之后插入了一个额外的 space 和发送的 headers:
bash> wget -S -d --header="If-Modified-Since: $if_modified_since" http://...
<snipped connection handshake>
---request begin---
GET ...
User-Agent: Wget/1.16.1 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: xxx.xxxxx.xxx
Connection: Keep-Alive
If-Modified-Since: Mon, 3 Aug 2015 08:45:18 GMT
---request end---
<snipped rest of response>
时间戳显然发送为:
Mon, 3 Aug 2015 08:45:18 GMT
额外的 space 使 If-Modified-Since
header 无法被接收服务器理解,因此被忽略。
最初倾向于认为 wget
是原因,但 hard-coding 值 Mon, 3 Aug 2015 08:45:18 GMT
按预期工作:
<snipped connection handshake>
---request begin---
GET ...
User-Agent: Wget/1.16.1 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: xxx.xxxxx.xxx
Connection: Keep-Alive
If-Modified-Since: Mon, 3 Aug 2015 08:45:18 GMT
---request end---
<snipped rest of response>
我怀疑 Mon
之后的逗号被特殊处理,但转义甚至删除它会导致相同的结果。我也知道Bash's brace expansion,但这里不是这样。
解决方法 1:使用 /bin/date
格式,其中日期为 2 位数字(%d
而不是 %e
):
bash> if_modified_since=`date --date="2 hours ago 5 minutes ago" +%a,\ %d\ %b\ %Y\ %H:%M:%S\ GMT`
bash> echo $ts_modified_since
Mon, 03 Aug 2015 09:13:30 GMT
解决方法 2:让 /bin/date
根据 RCF 2822 格式化时间戳,结果格式相同:
bash> if_modified_since_ts=`date --utc -R --date='5 minutes ago'`
bash> echo $ts_modified_since
Mon, 03 Aug 2015 09:13:30 GMT
两种解决方法都解决了问题:
bash> wget -S -d --header="If-Modified-Since: $if_modified_since" http://...
---request begin---
GET ....
User-Agent: Wget/1.16.1 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: xxx.xxxxxx.xxx
Connection: Keep-Alive
If-Modified-Since: Mon, 03 Aug 2015 09:13:30 GMT
---request end---
尽管如此,不管解决方法如何,为什么会首先发生这种情况?我在 bash 版本 4.3.30(1).
你的第二行:
bash> echo $if_modified_since
正在将内部空间融合为一个。尝试引用:
bash> echo "$if_modified_since"
我喜欢使用 date --date="2 hours ago 5 minutes ago" +%s
,它从不重复,不受时区或 DST 变化的影响,并且没有空格,减少了软件可能的错误解释。
当然,822格式是一种通用的时间交换格式(如果是UTC更好)。
但是,为什么不使用 wget 的自动时间戳检查呢?
您可以检查文件的时间戳,甚至更改它,wget 将检查 header 时间戳是否比文件时间戳更新。只需对 wget 使用 -N
。
注意:文件时间戳是这样读的:date -Rr $filename
R 为 rfc-822 风格,r 为参考(文件)。许多其他格式也是可能的。
这似乎是一个简单的引用问题。即:
$ if_modified_since=`date --date="2 hours ago 5 minutes ago" +%a,\ %e\ %b\ %Y\ %H:%M:%S\ GMT`
$ echo $if_modified_since # Shell performs word-splitting, echo sees 6 args
Mon, 3 Aug 2015 11:07:34 GMT
$ echo "$if_modified_since" # Shell does not perform word-splitting, echo sees 1 arg
Mon, 3 Aug 2015 11:07:34 GMT
也没有 "extra space",因为 %e
说明符被记录为对一位数字使用前导 space。来自 man strftime
:
%e Like %d, the day of the month as a decimal number, but a leading zero is
replaced by a space. (SU)
在 bash 提示符下我们有:
bash> if_modified_since=`date --date="2 hours ago 5 minutes ago" +%a,\ %e\ %b\ %Y\ %H:%M:%S\ GMT`
bash> echo $ts_modified_since
Mon, 3 Aug 2015 08:45:18 GMT
请注意 Mon,
和尾随 3 Aug...
之间有一个 space,这是预期的。
但是当尝试使用值 $if_modified_since
时,在 Mon,
之后插入了一个额外的 space 和发送的 headers:
bash> wget -S -d --header="If-Modified-Since: $if_modified_since" http://...
<snipped connection handshake>
---request begin---
GET ...
User-Agent: Wget/1.16.1 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: xxx.xxxxx.xxx
Connection: Keep-Alive
If-Modified-Since: Mon, 3 Aug 2015 08:45:18 GMT
---request end---
<snipped rest of response>
时间戳显然发送为:
Mon, 3 Aug 2015 08:45:18 GMT
额外的 space 使 If-Modified-Since
header 无法被接收服务器理解,因此被忽略。
最初倾向于认为 wget
是原因,但 hard-coding 值 Mon, 3 Aug 2015 08:45:18 GMT
按预期工作:
<snipped connection handshake>
---request begin---
GET ...
User-Agent: Wget/1.16.1 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: xxx.xxxxx.xxx
Connection: Keep-Alive
If-Modified-Since: Mon, 3 Aug 2015 08:45:18 GMT
---request end---
<snipped rest of response>
我怀疑 Mon
之后的逗号被特殊处理,但转义甚至删除它会导致相同的结果。我也知道Bash's brace expansion,但这里不是这样。
解决方法 1:使用 /bin/date
格式,其中日期为 2 位数字(%d
而不是 %e
):
bash> if_modified_since=`date --date="2 hours ago 5 minutes ago" +%a,\ %d\ %b\ %Y\ %H:%M:%S\ GMT`
bash> echo $ts_modified_since
Mon, 03 Aug 2015 09:13:30 GMT
解决方法 2:让 /bin/date
根据 RCF 2822 格式化时间戳,结果格式相同:
bash> if_modified_since_ts=`date --utc -R --date='5 minutes ago'`
bash> echo $ts_modified_since
Mon, 03 Aug 2015 09:13:30 GMT
两种解决方法都解决了问题:
bash> wget -S -d --header="If-Modified-Since: $if_modified_since" http://...
---request begin---
GET ....
User-Agent: Wget/1.16.1 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: xxx.xxxxxx.xxx
Connection: Keep-Alive
If-Modified-Since: Mon, 03 Aug 2015 09:13:30 GMT
---request end---
尽管如此,不管解决方法如何,为什么会首先发生这种情况?我在 bash 版本 4.3.30(1).
你的第二行:
bash> echo $if_modified_since
正在将内部空间融合为一个。尝试引用:
bash> echo "$if_modified_since"
我喜欢使用 date --date="2 hours ago 5 minutes ago" +%s
,它从不重复,不受时区或 DST 变化的影响,并且没有空格,减少了软件可能的错误解释。
当然,822格式是一种通用的时间交换格式(如果是UTC更好)。
但是,为什么不使用 wget 的自动时间戳检查呢?
您可以检查文件的时间戳,甚至更改它,wget 将检查 header 时间戳是否比文件时间戳更新。只需对 wget 使用 -N
。
注意:文件时间戳是这样读的:date -Rr $filename
R 为 rfc-822 风格,r 为参考(文件)。许多其他格式也是可能的。
这似乎是一个简单的引用问题。即:
$ if_modified_since=`date --date="2 hours ago 5 minutes ago" +%a,\ %e\ %b\ %Y\ %H:%M:%S\ GMT`
$ echo $if_modified_since # Shell performs word-splitting, echo sees 6 args
Mon, 3 Aug 2015 11:07:34 GMT
$ echo "$if_modified_since" # Shell does not perform word-splitting, echo sees 1 arg
Mon, 3 Aug 2015 11:07:34 GMT
也没有 "extra space",因为 %e
说明符被记录为对一位数字使用前导 space。来自 man strftime
:
%e Like %d, the day of the month as a decimal number, but a leading zero is
replaced by a space. (SU)