【问题标题】:In a unix shell, how to get yesterday's date into a variable?在 unix shell 中,如何将昨天的日期转换为变量?
【发布时间】:2011-03-31 21:15:16
【问题描述】:

我有一个 shell 脚本,它执行以下操作以将当前日期存储在变量 'dt' 中:

date "+%a %d/%m/%Y" | read dt
echo ${dt}

我将如何将 yesterdays 日期放入变量中?

基本上我想要实现的是使用 grep 从日志文件中提取所有昨天的行,因为日志中的每一行都包含“Mon 01/02/2010”格式的日期。

非常感谢

【问题讨论】:

  • Perl 是必要的选项...

标签: unix datetime shell ksh hp-ux


【解决方案1】:
dt=$(date --date yesterday "+%a %d/%m/%Y")
echo $dt

【讨论】:

  • +1 用于准确回答问题。需要注意的是,海报版本的 unix 可能不支持 -yesterday 标志
  • “-d昨天”的简短语法。
【解决方案2】:

在 Linux 上,您可以使用

date -d "-1 days" +"%a %d/%m/%Y"

【讨论】:

  • 这是所有其他答案中最好的答案,简短、甜美、简单、方便、酷,它证明了“给一个人一条鱼,他只吃一天,但教他钓鱼”的故事,他被喂了一辈子'
  • AIX 用户注意,date 不支持 -d 标志。
  • 谢谢。它有帮助。
【解决方案3】:

您可以使用如下所示的 GNU date 命令

获取过去的日期

要获取过去的昨天和更早的一天,请使用字符串 day ago:

日期 --date='昨天'

date --date='1 天前'

date --date='10 天前'

date --date='10 周前'

date --date='10 个月前'

date --date='10 年前'

获取未来的日期

要得到明天和后天(明天+N),用日字来获取未来的日期,如下:

日期 --date='明天'

date --date='1 天'

date --date='10 天'

date --date='10 周'

date --date='10 个月'

日期 --date='10 年'

【讨论】:

    【解决方案4】:

    如果您有 Perl 可用(并且您的 date 没有像 yesterday 这样的好功能),您可以使用:

    pax> date
    Thu Aug 18 19:29:49 XYZ 2010
    
    pax> dt=$(perl -e 'use POSIX;print strftime "%d/%m/%Y%",localtime time-86400;')
    
    pax> echo $dt
    17/08/2010
    

    【讨论】:

    • @Chris:请注意,这会为您提供 24 小时前的日期,这与昨天的日期略有不同。如果您的区域设置有夏令时,这将在冬季时间的第一天 23:00 之后给出错误的日期。
    • @Gilles,这不是一个坏点,因为我正在使用定位时间。如果你担心的话,你可以检查小时是否大于下午 6 点,只需减去 6 小时。这应该会涵盖它。
    • 好点的鳃。我想念我的 C# :DateTime.Now.AddDays(-1)
    • brew install coreutils 将 gnu 日期安装为 gdate。适用于 macOS 和 Linux。
    【解决方案5】:

    如果您使用的是 Mac 或 BSD 或其他没有 --date 选项的设备,您可以使用:

    date -r `expr \`date +%s\` - 86400` '+%a %d/%m/%Y'
    

    更新:或者……

    date -r $((`date +%s` - 86400)) '+%a %d/%m/%Y'
    

    【讨论】:

    • 使用$() 而不是` 会不会那么尴尬。 ksh 有$()?
    • +1 只是因为不假设每个 UNIX 问题都在 Linux 上。我们中的一些人还必须使用其他样式。
    • @paxdiablo:同意,但如果没有给出具体信息,我个人认为 GNU 工具包是一个选项;)HP-UXAIXSolaris 和 @987654329 之间的区别@ 很容易猜到味道。
    • 这会在奇怪的极端情况下失败吗?比如有闰秒?
    • $(( 算术扩展很好,但不是@bstpierre 所说的。即使在里面,您也应该真正使用$(...) 进行命令扩展:$(( $(date +%s) - 86400 ))
    【解决方案6】:

    我在 Linux 中有 shell 脚本,以下代码对我有用:

    #!/bin/bash
    yesterday=`TZ=EST+24 date +%Y%m%d` # Yesterday is a variable
    mkdir $yesterday # creates a directory with  YYYYMMDD format
    

    【讨论】:

    • TZ 是时区,EST+24 给出东部标准时间的昨天日期(同样,您可以使用 EST-24 表示明天的日期)+%Y%m%d 是 YYYYMMDD 的格式。
    • 对于任何正在寻找此类答案的人来说,这是迄今为止在 AIX 上工作的最简洁的版本。 AIX 不允许使用 -r 或 -d 标志,但实际上允许像这样操作时区!你让我很开心我一直在努力解决这个问题大约两个小时,我让一个日期显示为半年前,而其他想法不起作用。
    【解决方案7】:

    您至少有 2 个选项

    1. 使用 perl:

      perl -e '@T=localtime(time-86400);printf("%02d/%02d/%02d",$T[4]+1,$T[3],$T[5]+1900)'
      
    2. 安装 GNU 日期(如果我没记错,它在 sh_utils 包中)

      date --date yesterday "+%a %d/%m/%Y" | read dt
      echo ${dt}
      
    3. 不确定这是否有效,但您可以使用负时区。如果您使用比当前时区早 24 小时的时区,则可以简单地使用 date

    【讨论】:

    • @Chris:我认为它不会是与 GNU 兼容的 date,但由于您没有指定 Unix 变体,我只是猜想 ;) 使用 HP-UX,您的选择会更有限, date 没有这些选项,所以 Perl 可能是最好的选择。
    • 没关系,但如果你要在结果中添加1900,则不需要在年份中添加%100 :-)
    • @paxdiablo:公平点,Perl 显然不是我的强项之一;)我会 +1 你的答案。
    【解决方案8】:

    试试下面的方法:

    dt=`case "$OSTYPE" in darwin*) date -v-1d "+%s"; ;; *) date -d "1 days ago" "+%s"; esac`
    echo $dt
    

    它适用于 Linux 和 OSX。

    【讨论】:

      【解决方案9】:

      这是一个用于计算第一个参数的上一个日期的 ksh 脚本,在 Solaris 10 上进行了测试。

      #!/bin/ksh
       sep=""
       today=$(date '+%Y%m%d')
       today=${1:-today}
       ty=`echo $today|cut -b1-4` # today year
       tm=`echo $today|cut -b5-6` # today month
       td=`echo $today|cut -b7-8` # today day
       yy=0 # yesterday year
       ym=0 # yesterday month
       yd=0 # yesterday day
      
       if [ td -gt 1 ];
       then
               # today is not first of month
               let yy=ty       # same year
               let ym=tm       # same month
               let yd=td-1     # previous day
       else
               # today is first of month
               if [ tm -gt 1 ];
               then
                       # today is not first of year
                       let yy=ty       # same year
                       let ym=tm-1     # previous month
                       if [ ym -eq 1 -o ym -eq 3 -o ym -eq 5 -o ym -eq 7 -o ym -eq 8 -o ym -     eq 10 -o ym -eq 12 ];
                       then
                               let yd=31
                       fi
                       if [ ym -eq 4 -o ym -eq 6 -o ym -eq 9 -o ym -eq 11 ];
                       then
                               let yd=30
                       fi
                       if [ ym -eq 2 ];
                       then
                               # shit... :)
                               if [ ty%4 -eq 0 ];
                               then
                                       if [ ty%100 -eq 0 ];
                                       then
                                               if [ ty%400 -eq 0 ];
                                               then
                                               #echo divisible by 4, by 100, by 400
                                                       leap=1 
                                               else
                                               #echo divisible by 4, by 100, not by 400
                                                       leap=0
                                               fi
                                       else
                                               #echo divisible by 4, not by 100
                                               leap=1 
                                       fi
                               else
                                       #echo not divisible by 4
                                       leap=0 # not divisible by four
                               fi
                               let yd=28+leap
                       fi
               else
                       # today is first of year
                       # yesterday was 31-12-yy
                       let yy=ty-1     # previous year
                       let ym=12
                       let yd=31
               fi
       fi
       printf "%4d${sep}%02d${sep}%02d\n" $yy $ym $yd
      

      测试

      bin$ for date in 20110902 20110901 20110812 20110801 20110301 20100301 20080301 21000301 20000301 20000101 ; do yesterday $date; done
      20110901
      20110831
      20110811
      20110731
      20110228
      20100228
      20080229
      21000228
      20000229
      19991231
      

      【讨论】:

        【解决方案10】:

        感谢大家的帮助,但由于我使用的是 HP-UX(毕竟:支付的越多,获得的功能就越少……)我不得不求助于 perl:

        perl -e '@T=localtime(time-86400);printf("%02d/%02d/%04d",$T[3],$T[4]+1,$T[5]+1900)' | read dt
        

        【讨论】:

          【解决方案11】:

          如果您的 HP-UX 安装了 Tcl,您可能会发现它的日期运算非常可读(不幸的是,Tcl shell 没有像 perl 那样好的“-e”选项):

          dt=$(echo 'puts [clock format [clock scan yesterday] -format "%a %d/%m/%Y"]' | tclsh)
          echo "yesterday was $dt"
          

          这将处理所有的夏令时问题。

          【讨论】:

            【解决方案12】:

            如果您没有支持 --yesterday 的日期版本并且您不想使用 perl,您可以使用我的这个方便的 ksh 脚本。默认情况下,它返回昨天的日期,但你可以给它一个数字,它会告诉你过去多少天的日期。如果你看过去,它会开始放慢一点。 100,000 天前是 1738 年 1 月 30 日,但我的系统花了 28 秒才算出来。

                #! /bin/ksh -p
            
                t=`date +%j`
                ago=$1
                ago=${ago:=1} # in days
                y=`date +%Y`
            
                function build_year {
                        set -A j X $( for m in 01 02 03 04 05 06 07 08 09 10 11 12
                                {
                                        cal $m $y | sed -e '1,2d' -e 's/^/ /' -e "s/ \([0-9]\)/ $m\/\1/g"
                                } )
                        yeardays=$(( ${#j[*]} - 1 ))
                }
            
                build_year
            
                until [ $ago -lt $t ]
                do
                        (( y=y-1 ))
                        build_year
                        (( ago = ago - t ))
                        t=$yeardays
                done
            
                print ${j[$(( t - ago ))]}/$y
            

            【讨论】:

              【解决方案13】:

              ksh93:

              dt=${ printf "%(%a %d/%m/%Y)T" yesterday; }
              

              或:

              dt=$(printf "%(%a %d/%m/%Y)T" yesterday)
              

              第一个在同一个进程中运行,第二个在子shell中运行。

              【讨论】:

              • @clarkw:好建议,我会把它添加到答案中。
              【解决方案14】:

              对于 Hp-UX,只有以下命令对我有用:

              TZ=aaa24 日期 +%Y%m%d

              您可以将其用作:

              ydate=`TZ=aaa24 日期+%Y%m%d`

              回显 $ydate

              【讨论】:

                【解决方案15】:

                如果您有权访问 python,这是一个助手,它将获取任意 n 天前的 yyyy-mm-dd 日期值:

                function get_n_days_ago {
                  local days=$1
                  python -c "import datetime; print (datetime.date.today() - datetime.timedelta(${days})).isoformat()"
                }
                
                # today is 2014-08-24
                
                $ get_n_days_ago 1
                2014-08-23
                
                $ get_n_days_ago 2
                2014-08-22
                

                【讨论】:

                  【解决方案16】:
                  $var=$TZ;
                  TZ=$TZ+24;
                  date;
                  TZ=$var;
                  

                  昨天会在 AIX 中找到您并将 TZ 变量设置回原来的值

                  【讨论】:

                    【解决方案17】:

                    尽管所有答案都很好,但不幸的是,它们都不适合我。所以我不得不写一些老派的东西。 (我在一个简单的最小 Linux 操作系统上)

                    $ date -d @$( echo $(( $(date +%s)-$((60*60*24)) )) )
                    

                    您可以将它与日期的常用格式结合起来。例如。

                    $ date -d @$( echo $(( $(date +%s)-$((60*60*24)) )) ) +%Y-%m-%d
                    

                    说明: 以 epoc 秒( -d 选项)的形式输入日期,从中减去相当于一天的秒数。这将准确地返回一天的日期。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-11-09
                      • 1970-01-01
                      • 2020-12-02
                      • 1970-01-01
                      相关资源
                      最近更新 更多