【问题标题】:How to pass a range of dates through the for loop in bash?如何通过bash中的for循环传递一系列日期?
【发布时间】:2020-03-02 20:02:36
【问题描述】:

我是 Bash 新手,所以如果需要,请帮助我更好地阐明这个问题。

假设我有一个.sh 脚本。此脚本对从星期日到星期六的前一周的每一天的某些数据执行一些计算(该周从星期日开始)。例如今天,我正在为 2020 年 2 月 23 日至 2020 年 2 月 29 日的数据运行此脚本。在我的终端上运行脚本时,我提供了 3 个参数 - 年、月和日

./scriptname.sh ${yyyy} ${mm} ${dd}

现在,大多数时候,我可以接受这样的事情

yyyy=2020; mm=02; for dd in seq 23 -w 29; do ./scriptname.sh ${yyyy} ${mm} ${dd}; done

但几乎每个月都会有一周延续到下个月(例如从 3 月 29 日到 4 月 4 日的那一周)。起初我以为我可以使用变量将其自动化一点

start_day=$(date -d "last-sunday -7 days" +%d);
end_day=$(date -d "last-saturday" +%d);
start_month=$(date -d "last-sunday -7 days" +%m);
end_month=$(date -d "last-saturday" +%m);

所以上面的脚本变成了这样(为了格式化,必须排除 seq 周围的反引号)

yyyy=2020; for mm in  ${start_month} ${end_month}; do for dd in  seq -w ${start_day} ${end_day}; do ./scriptname.sh ${yyyy} ${mm} ${dd}; done; done

但它创建了ddmm 的所有排列。如何确保我只为${yyyy} ${mm} ${dd} 传递这 7 个相关值?

2020 03 29
2020 03 30
2020 03 31
2020 04 01
2020 04 02
2020 04 03
2020 04 04

【问题讨论】:

  • 您似乎知道seq。然后for i in $(seq 1 5).

标签: bash for-loop unix


【解决方案1】:

不要自己做。日期很棘手,月份的天数是可变的,等等。您的脚本还需要额外处理年份。让date 处理带有日期的计算。

for i in {1..7}; do ./scriptname.sh $(date --date="-$i days" "+%Y %m %d"); done

.g 从 3 月 29 日到 4 月 4 日这一周

我会这样做的方法是将第 29 场比赛作为自纪元以来的秒数。然后添加半天,以便闰秒(如果有的话)不是问题。然后只需将其增加一天中的秒数并使用date 将其转换回日期。

then=$(date --date='2020/03/29 12:00:00' +%s);
for i in {0..6}; do 
     ./scriptname.sh $(date --date="@$((then + $i * 60 * 60 * 24))" "+%Y %m %d");
done

或者,您可以不使用 then 变量来执行此操作,但您必须记住,紧跟在日期之后的数字 +0 被解释为时区。

for i in {0..6}; do ./scriptname.sh $(date --date="2020/03/29 12:00:00 +0 +$i days" '+%Y %m %d'); done

因为我喜欢 bash 中的流式解析,所以我会使用 xargs 解析输出:

seq 6 | xargs -I{} date -d '2020/03/29 12:00:00Z +{} days' '+%Y %m %d' | xargs -n3 ./scriptname.sh

【讨论】:

  • 我只需要提供年月日的值,所以我更喜欢第一种方法。照原样,它正在传递从 2020 02 24 到 2020 03 01 的日期范围。我需要的是 2020 02 23 到 2020 02 29(前一周的范围)如何修改它?
  • 第三个代码 sn-p 并不难理解。 {0..6} 是范围,而 2020/03/29 是当前日期,+$i days 表示将向前移动(而不是 -$i days).. 你想要 for i in {0..6}; do echo $(date --date="2020/02/29 12:00:00+0 -$i days" '+%Y %m %d'); done?还是for i in {0..6}; do echo $(date --date="2020/02/23 12:00:00+0 +$i days" '+%Y %m %d'); done
  • 好的,这确实给了我想要的预期输出,但看起来我必须手动指定今天的日期。对吗?
  • ?我不完全明白。你至少指定了一个日期。您开始的日期。或者你结束的日期。您指定的时间间隔始终为 7 天。你想要for i in {1..7}; do echo $(date --date="last-sunday -$i days" "+%Y %m %d"); done?真的,GNU date 的日期指定字符串非常...灵活。
  • 是的,可以修改。见我之前的评论。在这里(我住的地方)每周从星期一开始:for i in {0..6}; do echo $(date --date="last-monday +$i days" "+%Y %m %d %A"); done; )
【解决方案2】:

另一个例子,用秒计算天数:

for s in $(seq $(date -d "last-sunday -7 days" +%s) 86400 $(date -d "last-sunday" +%s)); do date --date=@$s "+%Y %m %d"; done

【讨论】:

  • 不得不将第二个“last-sunday”改为“last-saturday”,但我也喜欢这种方法。
猜你喜欢
  • 2017-02-19
  • 2021-08-21
  • 2013-07-19
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-12
  • 2014-10-05
相关资源
最近更新 更多