如何在不使用 if else 或 switch 或 while 循环的情况下使用 bash 获取当前年度每个月的最后一天?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12381501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:40:00  来源:igfitidea点击:

How to use bash to get the last day of each month for the current year without using if else or switch or while loop?

bashunix

提问by Hyman

As we know that each year have the following max day in each month as follows:

正如我们所知,每年每个月都有以下最大天数,如下所示:

Jan - 31 days
Feb - 28 days / 29 days (leap year)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days

How to I get bash to return the value (last day of each month) for the current year without using if elseor switchor whileloop?

如何在不使用if elseorswitchwhile循环的情况下让 bash 返回当前年份的值(每个月的最后一天)?

回答by glenn Hymanman

my take:

我的看法:

for m in {1..12}; do
  date -d "$m/1 + 1 month - 1 day" "+%b - %d days"; 
done

To explain: for the first iteration when m=1 the -dargument is "1/1 + 1 month - 1 day" and "1/1" is interpreted as Jan 1st. So Jan 1 + 1 month - 1 day is Jan 31. Next iteration "2/1" is Feb 1st, add a month subtract a day to get Feb 28 or 29. And so on.

解释一下:对于第一次迭代,当 m=1 时,-d参数是“1/1 + 1 个月 - 1 天”,“1/1”被解释为 1 月 1 日。所以 Jan 1 + 1 月 - 1 天是 1 月 31 日。下一次迭代“2/1”是 2 月 1 日,加上一个月减去一天得到 2 月 28 日或 29 日。依此类推。

回答by clyfish

cat <<EOF
Jan - 31 days
Feb - `date -d "yesterday 3/1" +"%d"` days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
EOF

回答by amdn

Assuming you allow "for", then the following in bash

假设您允许“for”,那么 bash 中的以下内容

for m in {1..12}; do
    echo $(date -d $m/1/1 +%b) - $(date -d "$(($m%12+1))/1 - 1 days" +%d) days
done

produces this

产生这个

 Jan - 31 days
 Feb - 29 days
 Mar - 31 days
 Apr - 30 days
 May - 31 days
 Jun - 30 days
 Jul - 31 days
 Aug - 31 days
 Sep - 30 days
 Oct - 31 days
 Nov - 30 days
 Dec - 31 days

Note: I removed the need for cal

注意:我删除了对 cal

For those that enjoy trivia:

对于那些喜欢琐事的人:

Number months from 1 to 12 and look at the binary representation in four
bits {b3,b2,b1,b0}.  A month has 31 days if and only if b3 differs from b0.
All other months have 30 days except for February.

So with the exception of February this works:

因此,除了二月,这都有效:

for m in {1..12}; do
    echo $(date -d $m/1/1 +%b) - $((30+($m>>3^$m&1))) days
done

Result:

结果:

Jan - 31 days
Feb - 30 days (wrong)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days

回答by crazyswissie

cal $(date +"%m %Y") |
awk 'NF {DAYS = $NF}; END {print DAYS}'

This uses the standard calutility to display the specified month, then runs a simple Awk script to pull out just the last day's number.

这使用标准cal实用程序来显示指定的月份,然后运行一个简单的 awk 脚本来提取最后一天的数字。

回答by Josiah DeWitt

returns the number of days in the month compensating for February changes in leap years without looping or using an if statement and only calls date once.

在不循环或不使用 if 语句且仅调用 date 一次的情况下,返回月份中补偿闰年二月变化的天数。

This code tests date to see if Feb 29th of the requested year is valid, if so then it updates the second character in the day offset string. The month argument selects the respective substring and adds the month difference to 28.

此代码测试日期以查看请求年份的 2 月 29 日是否有效,如果有效,则更新日期偏移字符串中的第二个字符。月份参数选择相应的子字符串并将月差添加到 28。

function daysin()
{
   s="303232332323"                                        # normal year
   date -d "2/29/" > /dev/null 2>&1 && s="313232332323"  # leap year
   echo $[ ${s:$[-1]:1} + 28 ]
}

daysin                                                 #daysin [1-12] [YYYY]

回答by Walk

Try using this code

尝试使用此代码

date -d "-$(date +%d) days  month" +%Y-%m-%d

回答by Steve

Contents of script.sh:

内容script.sh

#!/bin/bash
begin="-$(date +'%-m') + 2"
end="10+$begin"

for ((i=$begin; i<=$end; i++)); do
    echo $(date -d "$i month -$(date +%d) days" | awk '{ printf "%s - %s days", ,  }')
done

Results:

结果:

Jan - 31 days
Feb - 29 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days

回答by Valentin Heinitz

for m in $(seq 1 12); do cal  $(date +"$m %Y") | grep -v "^$" |tail -1|grep -o "..$"; done
  • iterate from 1 to 12 (for...)
  • print calendar table for each month (cal...)
  • remove empty lines from output (grep -v...)
  • print last number in the table (tail...)
  • 从 1 到 12 迭代(对于...)
  • 打印每个月的日历表(cal...)
  • 从输出中删除空行 (grep -v...)
  • 打印表中的最后一个数字(尾部...)

There is no sense, to avoid using cal, because it is required by POSIX, so should be there

没有意义,避免使用cal,因为POSIX需要它,所以应该有

回答by atmosx

On a Mac which features BSD dateyou can just do:

在具有BSD 日期功能的 Mac 上,您可以执行以下操作:

for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done

Quick Explanation

快速说明

-vstands for adjust. We are adjusting the date to:

-v代表调整。我们将日期调整为:

-v1dstands for first day of the month

-v1d代表一个月的第一天

-v"$i"mdefined the month e.g. (-v2mfor Feb)

-v"$i"m定义月份,例如(-v2m对于二月)

-v-1dminus one day (so we're getting the last day of the previous month)

-v-1d减去一天(所以我们得到上个月的最后一天)

"+%d"print the day of the month

"+%d"打印一个月中的哪一天

for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done
31
28
31
30
31
30
31
31
30
31
30

You can add year of course. See examples in the manpage (link above).

您当然可以添加年份。请参阅联机帮助页中的示例(上面的链接)。

回答by Sharuzzaman Ahmat Raslan

A variation for the accepted answer to show the use of "yesterday"

已接受答案的变体,以显示“昨天”的使用

$ for m in {1..12}; do date -d "yesterday $m/1 + 1 month" "+%b - %d days"; done
Jan - 31 days
Feb - 28 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days

How it works?

这个怎么运作?

Show the date of yesterday for the date "month/1" after adding 1 month

添加 1 个月后,为日期“月/1”显示昨天的日期