在 bash 脚本中查找本月的最后一个星期六
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13003217/
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
Find the last Saturday of the month in a bash script
提问by Jompa
I'm making a backup script in which I need to find the last Saturday of each month.
我正在制作一个备份脚本,我需要在其中找到每个月的最后一个星期六。
I've tried different approaches to finding the day itself, which works splendidly themselves.
我尝试了不同的方法来寻找这一天,这本身就非常有效。
The problem is, when I try putting them into my script I always get the error code
./test.sh: line 13: [: 29: integer expression expected.
问题是,当我尝试将它们放入我的脚本时,我总是收到错误代码
./test.sh: line 13: [: 29: integer expression expected。
This is my code:
这是我的代码:
#!/bin/bash
LASTSAT=$(ncal | grep Sa | awk '{print$(NF-0)}')
SATURDAY="6"
DAY=$(date +"%u")
DATE=$(date +"%d")
echo "$DAY"
echo "$DATE"
echo "$LASTSAT"
if [ $DATE -eq $LASTSAT ]
then
echo "sista l?rdagen..."
fi
I got the tip to change the if statements to [ "$DATE" = "$LASTSAT" ]which erased the error itself, but the script will somehow not equal 27 to 27 (to take this month as an example).
我得到了将 if 语句更改为[ "$DATE" = "$LASTSAT" ]删除错误本身的提示,但脚本不知何故将不等于 27 到 27(以本月为例)。
I also tried another approach to finding the last Saturday which was LASTSAT=$(cal|awk '{if(NF==7){SAT=$7}};END{print SAT}'), but it returns the exact same error if I use -eq and doesn't equal 27 to 27 using " with =
我也尝试另一种方法来找到最后一个星期六这是LASTSAT=$(cal|awk '{if(NF==7){SAT=$7}};END{print SAT}')的,但如果我使用当量,并使用不等于27至27“与=返回确切的同样的错误
I'm very confused and out of ideas and I have searched the internet and copied the exact lines others been using but it all ends up the same.
我很困惑,没有想法,我在互联网上搜索并复制了其他人使用的确切线路,但结果都是一样的。
What am I doing wrong?
我究竟做错了什么?
采纳答案by James Waldby - jwpat7
During testing I changed the target day and some of the variable names, but the following script works, for the next-to-last Sunday of the month. The critical change, relative to your script, was adding the -hswitch to ncal, to turn off highlighting of the current day. The highlighting characters apparently come through when awkprints the field, but aren't visible when you do the echos. Note, you can drop the grepafter ncalvia an awkmatch.
在测试期间,我更改了目标日期和一些变量名称,但以下脚本适用于该月的倒数第二个星期日。与您的脚本相关的关键更改是将-h开关添加到ncal, 以关闭当天的突出显示。awk打印字段时突出显示的字符显然会出现,但在执行echos时不可见。请注意,您可以通过匹配删除grepafter 。ncalawk
#!/bin/bash
DoDay=$(ncal -h |awk '/Su/ {print $(NF-1)}')
Datum=$(date +%d)
echo $Datum Datum
echo $DoDay DoDay
if [[ $Datum == $DoDay ]]
then
echo "sista l?rdagen..."
else
echo "doh"
fi
回答by Steve
Here's one way to print the last Saturday in each month using date:
这是使用以下方法打印每个月的最后一个星期六的一种方法date:
for i in {1..12}; do
for j in {1..7}; do
date=$(date -d "$i/1 + 1 month - $j day" +"%w %F")
# day of week (1..7); 1 is Monday
if [ ${date:0:1} -eq 6 ]; then
echo ${date:2}
fi
done
done
Results:
结果:
2012-01-28
2012-02-25
2012-03-31
2012-04-28
2012-05-26
2012-06-30
2012-07-28
2012-08-25
2012-09-29
2012-10-27
2012-11-24
2012-12-29
If you'd just like to find the last Saturday in the current month, try:
如果您只想查找当月的最后一个星期六,请尝试:
for j in {1..7}; do
month=$(date +"%m")
date=$(date -d "$month/1 + 1 month - $j day" +"%w %F")
# day of week (1..7); 1 is Monday
if [ ${date:0:1} -eq 6 ]; then
echo ${date:2}
fi
done
Result:
结果:
2012-10-27
Please note, that you can change the output format of these results in the above scripts simply by changing %Fto any of the formats datehas to offer. See man date.
请注意,您可以通过更改%F为date必须提供的任何格式来更改上述脚本中这些结果的输出格式。见man date。
回答by ghoti
You can easily get the last Saturday of the month using the datecommand, which spits out data in strftime()format. But date's syntax will depend on your operating system.
您可以使用该date命令轻松获取该月的最后一个星期六,该命令以strftime()格式输出数据。但是date的语法将取决于您的操作系统。
In FreeBSD or OSX, there's a -voption to "adjust" the date that gives you lots of control:
在 FreeBSD 或 OSX 中,有一个-v选项可以“调整”日期,让您有很多控制权:
[ghoti@pc ~]$ date -v+1m -v1d -v6w '+%a %d %b %Y'
Sat 03 Nov 2012
[ghoti@pc ~]$ date -v+1m -v1d -v6w -v-1w '+%a %d %b %Y'
Sat 27 Oct 2012
The idea here is that we'll move 1 month forward (+1m), back up to the first of the month (1d), then move to the 6th day of the week which is Saturday (6w). For demonstration purposes, the first line shows the first saturday of next month, and the second line shows the date one week(-v-1w) earlier.
这里的想法是我们将向前移动 1 个月 ( +1m),回到本月的第一天 ( 1d),然后移动到一周的第 6 天,即星期六 ( 6w)。出于演示目的,第一行显示下个月的第一个星期六,第二行显示一周前( -v-1w)的日期。
Alternately, if you wanted to put some math in your bash script, you could do something like this:
或者,如果您想在 bash 脚本中加入一些数学运算,您可以执行以下操作:
#!/usr/local/bin/bash
# Get day-of-the-week for the first-of-the-month:
firstofmonth=$(date -j -v+1m -v1d '+%u')
# ^
# + This is the relative month to current.
# Subtract this from 7 to find the date of the month
firstsaturday=$((7 - $firstofmonth))
# 7 days before that will be the last Saturday of the previous month
lastsaturday=$(date -j -v+1m -v${firstsaturday}d -v-7d '+%Y-%m-%d')
With the -voption, 1 is January, 2 is February, etc. Or it can be relative, as I've shown here, with +1 for next month, -1 for last month, etc.
有了这个-v选项,1 是一月,2 是二月,等等。或者它可以是相对的,正如我在这里展示的,下个月 +1,上个月 -1,等等。
In Linux, date uses a -doption that interprets a text description of the date. So:
在 Linux 中, date 使用一个-d选项来解释日期的文本描述。所以:
#!/bin/bash
firstofmonth=$(date -d '+1 months' '+%Y%m01')
firstsaturday=$(date -d "$firstofmonth" '+%Y-%m')-$(( 7 - $(date -d "$firstofmonth" '+%u') ))
lastsaturday=$(date -d "$firstsaturday -7 days" '+%d')
Note that if you're using cron, you can simplify this. You know that the last Saturday will sit within the last 7 days of the month, so we can start by using cron to limit things to Saturday, then check for the last of the month within the script. This will runthe script every Saturday, but it will do nothing except when it's supposed to. The cron tab would be, say,
请注意,如果您使用的是 cron,则可以简化此操作。您知道最后一个星期六将位于该月的最后 7 天,因此我们可以首先使用 cron 将事情限制在星期六,然后在脚本中检查本月的最后一天。这将在每个星期六运行脚本,但除了应该执行的时候,它什么都不做。cron 选项卡将是,说,
# ↙ "0 0"=midnight
0 0 * * 0 /path/to/script.sh
# ↖ 0=Sunday
And script.shwould start with:
并script.sh会开始:
#!/bin/bash
if [[ $(date '+%d' -lt $(date -d "$(date -d '+1 month' '+%Y%m01') -7 days" '+%d') ]]; then
exit
fi
You could also put this test within the crontab, though it would look a little uglier because you'd need to escape the percent signs:
你也可以把这个测试放在 crontab 中,虽然它看起来有点难看,因为你需要转义百分号:
0 0 * * 0 \
test $(date '+\%d') -ge $(date -d "$(date -d '+1 month' '+\%Y\%m01') -7 days" '+\%d') \
&& /path/to/command
回答by rici
How about this one:
这个怎么样:
last_saturday ()
{
local Format;
if [[ =~ ^\+.* ]]; then
Format=;
shift;
fi;
local FirstOfNext="${1:-$(date +%B)} 1 + 1 month";
date $Format -d "$FirstOfNext - 1 day -
$(($(date +%u -d "$FirstOfNext") % 7)) day"
}
eg:
例如:
$ last_saturday
Sat Oct 27 00:00:00 PET 2012
$ last_saturday November
Sat Nov 24 00:00:00 PET 2012
$ last_saturday June
Sat Jun 23 00:00:00 PET 2012
$ last_saturday June 2013
Sat Jun 29 00:00:00 PET 2013
$ last_saturday +%Y-%m-%d June 2013
2013-06-29
回答by agirish
The script works fine on my System (Ubuntu - Bash $).
I just modified the script to print "!sista l?rdagen..." if the day wasn't the last saturday and this was the output:
$sh abc.sh
7
21
27
!sista lordagen...
该脚本在我的系统(Ubuntu - Bash $)上运行良好。我只是修改了脚本以打印“!sista l?rdagen...”,如果这一天不是最后一个星期六,这是输出:
$sh abc.sh
7
21
27
!sista lordagen...
回答by marian kamenistak
#!/bin/bash
set -e
if [ "$#" -ne 2 ]; then
echo "Usage: weekDayOfMonth.sh [weekOfMonth 1..4] [DayOfWeek where Sun=1]"
exit 2;
fi
weekOfMonth=
dayOfWeek= #starts with Sun(=1)
echo "weekOfMonth: $weekOfMonth";
echo "dayOfWeek: $dayOfWeek";
# cal starts with Sun, 3rd column is for Tue, 2nd row is 2nd Tue of month:
# Sun=1, dayIdx=0
# Mon=2, dayIdx=3
# Tue=3, dayIdx=6
# Wed=4, dayIdx=9
dayIdx=$(((dayOfWeek-1)*3))
expectedDayOfMonth=$(cal -s | sed "s/^.\{$dayIdx\}\(.\{3\}\).*$//" | sed 's/^[ ]//g' | grep -o '[0-9]*' | head -$weekOfMonth | tail -1)
todaysDay=$(date +%d | sed 's/^0*//')
echo "expectedDayOfMonth: $expectedDayOfMonth";
echo "todaysDay: $todaysDay";
if [ ${expectedDayOfMonth} -ne ${todaysDay} ]; then
echo "Today is NOT requested day of month, exiting with error code.";
exit 1;
fi
回答by user10145222
How about this one:
这个怎么样:
if [ `date +%u` = 7 ] && [ `date +%m` != `date -d +week +%m` ]; then
echo "sista l?rdagen..."
fi
... or simply via crontab:
... 或者只是通过 crontab:
0 0 * * 0 [ `date +\%m` != `date -d +week +\%m` ] && /path/to/backup.sh

