在bash脚本中查找该月的最后一个星期六

时间:2012-10-21 23:24:32

标签: bash shell

我正在编写一个备份脚本,我需要找到每个月的最后一个星期六。

我尝试过不同的方法来找到这一天,这本身就很出色。

问题是,当我尝试将它们放入我的脚本时,我总是得到错误代码 ./test.sh: line 13: [: 29: integer expression expected

这是我的代码:

#!/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

我得到了将if语句更改为[ "$DATE" = "$LASTSAT" ]的提示 它删除了错误本身,但脚本将以某种方式不等于27到27(以本月为例)。

我还尝试了另一种方法来查找上一个星期六LASTSAT=$(cal|awk '{if(NF==7){SAT=$7}};END{print SAT}'),但如果我使用-eq并且使用“with =

不等于27到27,则会返回完全相同的错误

我非常困惑并且没有想法,我搜索了互联网并复制了其他人正在使用的确切行,但这一切都结束了。

我做错了什么?

8 个答案:

答案 0 :(得分:2)

在测试期间,我更改了目标日期和一些变量名称,但以下脚本适用于该月的倒数第二个星期日。相对于您的脚本,关键更改是将-h切换添加到ncal,以关闭当天的突出显示。当awk打印字段时,突出显示的字符显然会出现,但在执行echo时则不可见。请注意,您可以通过grep匹配在ncal之后删除awk

#!/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

答案 1 :(得分:2)

以下是使用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

结果:

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

如果您只想查找当月的最后一个星期六,请尝试:

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

结果:

2012-10-27

请注意,您只需将%F更改为date提供的任何格式,即可在上述脚本中更改这些结果的输出格式。请参阅man date

答案 2 :(得分:2)

您可以使用date命令轻松获取当月的最后一个星期六,该命令以strftime()格式吐出数据。但date的语法取决于您的操作系统。

在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

这里的想法是我们将向前移动1个月(+1m),然后回到本月的第一天(1d),然后移动到本周的第6天,即星期六(6w)。出于演示目的,第一行显示下个月的第一个星期六,第二行显示日期一周-v-1w)。

或者,如果你想在你的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')

使用-v选项,1是1月,2是2月等。或者它可以是相对的,如我在此处所示,下个月为+1,上个月为-1,等等。


在Linux 中,日期使用-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')

请注意,如果您使用的是cron ,则可以简化此操作。您知道上个星期六将在本月的最后7天内进行,因此我们可以首先使用cron将事情限制为星期六,然后检查脚本中的最后一个月。这将在每个星期六运行脚本,但除了应该这样做之外什么都不做。例如,cron选项卡将是

#  ↙ "0 0"=midnight
0 0 * * 0 /path/to/script.sh
#        ↖ 0=Sunday

script.sh将以:

开头
#!/bin/bash

if [[ $(date '+%d' -lt $(date -d "$(date -d '+1 month' '+%Y%m01') -7 days" '+%d') ]]; then
  exit
fi

你也可以把这个测试放在crontab中,虽然它看起来有点丑陋,因为你需要逃避百分号:

0 0 * * 0 \
  test $(date '+\%d') -ge $(date -d "$(date -d '+1 month' '+\%Y\%m01') -7 days" '+\%d') \
    && /path/to/command

答案 3 :(得分:1)

这个怎么样:

last_saturday () 
{ 
    local Format;
    if [[ $1 =~ ^\+.* ]]; then
        Format=$1;
        shift;
    fi;
    local FirstOfNext="${1:-$(date +%B)} 1 $2 + 1 month";
    date $Format -d "$FirstOfNext - 1 day - 
                     $(($(date +%u -d "$FirstOfNext") % 7)) day"
}

例如:

$ 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

答案 4 :(得分:0)

该脚本在我的系统上运行正常(Ubuntu - Bash $)。 我刚刚修改了脚本以打印“!sistalördagen...”如果那天不是最后一个星期六,这是输出:
$ sh abc.sh
7
21
27
!sista lordagen ......

答案 5 :(得分:0)

#!/bin/bash
set -e

if [ "$#" -ne 2 ]; then
    echo "Usage: weekDayOfMonth.sh [weekOfMonth 1..4] [DayOfWeek where Sun=1]"
    exit 2;
fi

weekOfMonth=$1
dayOfWeek=$2 #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\}\).*$/\1/" | 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

答案 6 :(得分:0)

解决办法

if  [[ $(date +"%a") = "Sat" ]] && [[$(date -d "+7 days" +%m) != $(date +%m)]]
then
  echo "Last saturday of month"
fi

答案 7 :(得分:-1)

这个怎么样?

if [ `date +%u` = 7 ] && [ `date +%m` != `date -d +week +%m` ]; then
  echo "sista lördagen..."
fi

...或仅通过crontab:

0 0 * * 0 [ `date +\%m` != `date -d +week +\%m` ] && /path/to/backup.sh