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)