在 bash 中使用 bash 循环迭代日期 - for (( ... )) 无法正常工作
Iterating over dates with a bash loop in bash -- for (( ... )) not working correctly
我正在尝试创建一个日期列表。下面的脚本适用于没有空格的简单日期。
datestart=20130601
dateend=20130705
for (( date1="$datestart"; date1 != dateend; )); do
date1="$(date --date="$date1 + 1 days" +'%Y%m%d')";
echo $date1;
done
当我使用像(包含 WHITE SPACE)datestart="2013-06-01 00:00:00" 这样的数据字符串和像 +'Y-%m-%d %H:%M:%S'[=15 这样的日期格式时=]
datestart="2013-06-01 00:00:00"
dateend="2013-07-05 00:00:00"
for (( date1="$datestart"; date1 != "$dateend"; )); do
date1="$(date --date=""$date1" + 1 days" +'%Y-%d-%m %H:%M:%S')";
echo "$date1";
done
我收到以下错误:
-bash: ((: date1=2013-06-01 00:00:00: syntax error in expression (error token is "00:00:00")
我想我没有正确引用我的变量。我胡思乱想,现在我在这里。如何在 for 循环中正确引用变量?
不可能,bash 三表达式 for 循环需要算术表达式。看到这个 link:
http://wiki.bash-hackers.org/syntax/ccmd/c_for
改用经典的 "while" 循环。
附录
您可以使用纪元中的秒数来允许算术,例如:
datestart=$(date --date="2013-06-01 00:00:00" +%s)
dateend=$(date --date="2013-07-05 00:00:00" +%s)
for (( date1=$datestart; date1 != $dateend; date1+=86400 )); do
date --date=@$date1
done
但要注意没有 86400 秒的日子。
这应该适合你:
datestart="2013-06-01 00:00:00"
dateend="2013-07-05 00:00:00"
date1="$datestart"
while [[ "$date1" != "$dateend" ]]; do
date1="$(date -u --date="$date1 tomorrow" '+%Y-%m-%d %H:%M:%S')"
echo "$date1"
done
((...))
仅用于算术运算。请改用 while
循环。
- 无需为
$date
使用嵌套引号
- 使用
tomorrow
获取下一个日期
- 在将下一个日期分配给
date1
时使用正确的 year-month-date
格式
关于你的报价被关闭,你是对的。你有:
date1="$(date --date=""$date1" + 1 days" +'%Y-%d-%m %H:%M:%S')";
但是你正在以非常奇怪的方式使用双引号。一个快速的解决方案可能是切换到单引号,如果变量在双引号内,它不会隔离变量:
date1="$(date --date="'$date1' + 1 days" +'%Y-%d-%m %H:%M:%S')";
至于其他部分...让我们回顾一下 bash 手册页上的内容:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
First, the arithmetic expression expr1 is evaluated according to
the rules described below under ARITHMETIC EVALUATION. ...
如果您查看手册页的 ARITHMETIC EVALUATION
部分,您会发现它不 包含 /bin/test 的各种测试或者 [[ ... ]]
可以 运行。这些内容在手册页的下一部分 CONDITIONAL EXPRESSIONS
.
中介绍
如果你想使用 for
循环,那么我也会使用 @pasaba 的建议使用纪元秒,以便坚持算术。像这样:
#!/bin/bash
datestart="2013-06-01 00:00:00"
dateend="2013-07-05 00:00:00"
e_start=$(date -d "$datestart" '+%s')
e_end=$(date -d "$dateend" '+%s')
for (( date1=$e_start; date1 < $e_end; date1+=86400 )); do
echo -n "$date1 "; date -d "@$date1" '+%Y-%m-%d'
done
考虑到闰年和闰秒等,你可以相信 Linux date
命令,并像你原来那样在循环中计算 $date1
:
for (( date1=$e_start; date1 < $e_end; )); do
date1=$(date -d "$(date -d "@$date1") + 1 day" '+%s')
echo -n "$date1 "; date -d "@$date1" '+%Y-%m-%d'
done
嵌套的 date
命令是必需的,因为 Linux 的 date
命令不允许您使用相对日期(“+1day”或 "tomorrow")当起始日期指定为 @
的纪元时。 (我很想知道我是否错了。)
我知道你的问题被标记为 "Linux",但我会在以后的搜索中注意到这是 date
的不可移植(Linux-only)使用命令,因此如果您希望此脚本在 FreeBSD、NetBSD、OSX 等中 运行,您需要查看它们的用法。以下适用于 FreeBSD:
#!/usr/bin/env bash
datestart="2015-06-01 00:00:00"
dateend="2015-07-05 00:00:00"
e_start="$(date -jf '%Y-%m-%d %T' "$datestart" '+%s')"
e_end="$(date -jf '%Y-%m-%d %T' "$dateend" '+%s')"
for (( date1 = $e_start; date1 < $e_end; )); do
date1=$(date -j -v+1d -f '%s' "$date1" '+%s')
echo -n "$date1 "; date -jf '%s' "$date1" '+%Y-%m-%d'
done
我正在尝试创建一个日期列表。下面的脚本适用于没有空格的简单日期。
datestart=20130601
dateend=20130705
for (( date1="$datestart"; date1 != dateend; )); do
date1="$(date --date="$date1 + 1 days" +'%Y%m%d')";
echo $date1;
done
当我使用像(包含 WHITE SPACE)datestart="2013-06-01 00:00:00" 这样的数据字符串和像 +'Y-%m-%d %H:%M:%S'[=15 这样的日期格式时=]
datestart="2013-06-01 00:00:00"
dateend="2013-07-05 00:00:00"
for (( date1="$datestart"; date1 != "$dateend"; )); do
date1="$(date --date=""$date1" + 1 days" +'%Y-%d-%m %H:%M:%S')";
echo "$date1";
done
我收到以下错误:
-bash: ((: date1=2013-06-01 00:00:00: syntax error in expression (error token is "00:00:00")
我想我没有正确引用我的变量。我胡思乱想,现在我在这里。如何在 for 循环中正确引用变量?
不可能,bash 三表达式 for 循环需要算术表达式。看到这个 link:
http://wiki.bash-hackers.org/syntax/ccmd/c_for
改用经典的 "while" 循环。
附录
您可以使用纪元中的秒数来允许算术,例如:
datestart=$(date --date="2013-06-01 00:00:00" +%s)
dateend=$(date --date="2013-07-05 00:00:00" +%s)
for (( date1=$datestart; date1 != $dateend; date1+=86400 )); do
date --date=@$date1
done
但要注意没有 86400 秒的日子。
这应该适合你:
datestart="2013-06-01 00:00:00"
dateend="2013-07-05 00:00:00"
date1="$datestart"
while [[ "$date1" != "$dateend" ]]; do
date1="$(date -u --date="$date1 tomorrow" '+%Y-%m-%d %H:%M:%S')"
echo "$date1"
done
((...))
仅用于算术运算。请改用while
循环。- 无需为
$date
使用嵌套引号
- 使用
tomorrow
获取下一个日期 - 在将下一个日期分配给
date1
时使用正确的
year-month-date
格式
关于你的报价被关闭,你是对的。你有:
date1="$(date --date=""$date1" + 1 days" +'%Y-%d-%m %H:%M:%S')";
但是你正在以非常奇怪的方式使用双引号。一个快速的解决方案可能是切换到单引号,如果变量在双引号内,它不会隔离变量:
date1="$(date --date="'$date1' + 1 days" +'%Y-%d-%m %H:%M:%S')";
至于其他部分...让我们回顾一下 bash 手册页上的内容:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
First, the arithmetic expression expr1 is evaluated according to
the rules described below under ARITHMETIC EVALUATION. ...
如果您查看手册页的 ARITHMETIC EVALUATION
部分,您会发现它不 包含 /bin/test 的各种测试或者 [[ ... ]]
可以 运行。这些内容在手册页的下一部分 CONDITIONAL EXPRESSIONS
.
如果你想使用 for
循环,那么我也会使用 @pasaba 的建议使用纪元秒,以便坚持算术。像这样:
#!/bin/bash
datestart="2013-06-01 00:00:00"
dateend="2013-07-05 00:00:00"
e_start=$(date -d "$datestart" '+%s')
e_end=$(date -d "$dateend" '+%s')
for (( date1=$e_start; date1 < $e_end; date1+=86400 )); do
echo -n "$date1 "; date -d "@$date1" '+%Y-%m-%d'
done
考虑到闰年和闰秒等,你可以相信 Linux date
命令,并像你原来那样在循环中计算 $date1
:
for (( date1=$e_start; date1 < $e_end; )); do
date1=$(date -d "$(date -d "@$date1") + 1 day" '+%s')
echo -n "$date1 "; date -d "@$date1" '+%Y-%m-%d'
done
嵌套的 date
命令是必需的,因为 Linux 的 date
命令不允许您使用相对日期(“+1day”或 "tomorrow")当起始日期指定为 @
的纪元时。 (我很想知道我是否错了。)
我知道你的问题被标记为 "Linux",但我会在以后的搜索中注意到这是 date
的不可移植(Linux-only)使用命令,因此如果您希望此脚本在 FreeBSD、NetBSD、OSX 等中 运行,您需要查看它们的用法。以下适用于 FreeBSD:
#!/usr/bin/env bash
datestart="2015-06-01 00:00:00"
dateend="2015-07-05 00:00:00"
e_start="$(date -jf '%Y-%m-%d %T' "$datestart" '+%s')"
e_end="$(date -jf '%Y-%m-%d %T' "$dateend" '+%s')"
for (( date1 = $e_start; date1 < $e_end; )); do
date1=$(date -j -v+1d -f '%s' "$date1" '+%s')
echo -n "$date1 "; date -jf '%s' "$date1" '+%Y-%m-%d'
done