【问题标题】:Change date format in first column using awk/sed使用 awk/sed 更改第一列中的日期格式
【发布时间】:2026-01-02 10:40:02
【问题描述】:

我有一个每天早上自动运行的 shell 脚本,它将当天的结果附加到一个文本文件中。该文件的第一列应该有今天的日期,然后是用逗号分隔的结果。我使用命令 date +%x 以所需格式 (dd/mm/yy) 获取日期。但是在一台计算机上 date +%x 返回 mm/dd/yyyy (知道为什么会这样吗?)。然后我按日期顺序对文件中的数据进行排序。

这是这样一个文本文件的sn-p

29/11/12,9654.80,194.32,2.01,7.19,-7.89,7.65,7.57,3.98,9625.27,160.10,1.66,4.90,-4.79,6.83,4.84,3.54                
03/12/12,5184.22,104.63,2.02,6.88,-6.49,7.87,6.67,4.10,5169.52,93.81,1.81,5.29,-5.45,7.87,5.37,4.10                
04/12/12,5183.65,103.18,1.99,6.49,-6.80,8.40,6.66,4.38,5166.04,95.44,1.85,6.04,-6.49,8.40,6.28,4.38                
11/07/2012,5183.65,102.15,1.97,6.78,-6.36,8.92,6.56,4.67,5169.48,96.67,1.87,5.56,-6.10,8.92,5.85,4.67                
07/11/2012,5179.39,115.57,2.23,7.64,-6.61,8.83,7.09,4.62,5150.17,103.52,2.01,7.01,-6.08,8.16,6.51,4.26                
11/26/2012,5182.66,103.30,1.99,7.07,-5.76,7.38,6.37,3.83,5162.81,95.47,1.85,6.34,-5.40,6.65,5.84,3.44                
11/30/2012,5180.82,95.19,1.84,6.51,-5.40,7.91,5.92,4.12,5163.98,91.82,1.78,5.58,-5.07,7.05,5.31,3.65     

是否可以使用 awk 或 sed 将后四行的日期格式更改为正确的日期格式?我只想将 mm/dd/yyyy 格式的日期格式更改为 dd/mm/yy。

【问题讨论】:

    标签: linux sed awk


    【解决方案1】:

    您似乎正在使用date 的两种不同风格(版本)。要检查您有哪些版本,我认为 GNU date 接受 --version 标志,而其他版本,如 BSD/OSX 将不接受此标志。

    由于您可能使用完全不同的系统,因此完全避免使用date 并使用perl 打印当前日期可能是最安全的:

    perl -MPOSIX -e 'print POSIX::strftime("%d/%m/%y", localtime) . "\n"'
    

    如果你确定你在两台机器上都有GNU awk,你可以这样使用它:

    awk 'BEGIN { print strftime("%d/%m/%y") }'
    

    要修复您拥有的文件,这是我使用GNU awk 的方法:

    awk '{ print gensub(/^(..\/)(..\/)..(..,)/, "\\2\\1\\3", "g"); next }1' file
    

    或者使用sed:

    sed 's/^\(..\/\)\(..\/\)..\(..,\)/\2\1\3/' file
    

    结果:

    29/11/12,9654.80,194.32,2.01,7.19,-7.89,7.65,7.57,3.98,9625.27,160.10,1.66,4.90,-4.79,6.83,4.84,3.54                
    03/12/12,5184.22,104.63,2.02,6.88,-6.49,7.87,6.67,4.10,5169.52,93.81,1.81,5.29,-5.45,7.87,5.37,4.10                
    04/12/12,5183.65,103.18,1.99,6.49,-6.80,8.40,6.66,4.38,5166.04,95.44,1.85,6.04,-6.49,8.40,6.28,4.38                
    07/11/12,5183.65,102.15,1.97,6.78,-6.36,8.92,6.56,4.67,5169.48,96.67,1.87,5.56,-6.10,8.92,5.85,4.67                
    11/07/12,5179.39,115.57,2.23,7.64,-6.61,8.83,7.09,4.62,5150.17,103.52,2.01,7.01,-6.08,8.16,6.51,4.26                
    26/11/12,5182.66,103.30,1.99,7.07,-5.76,7.38,6.37,3.83,5162.81,95.47,1.85,6.34,-5.40,6.65,5.84,3.44                
    30/11/12,5180.82,95.19,1.84,6.51,-5.40,7.91,5.92,4.12,5163.98,91.82,1.78,5.58,-5.07,7.05,5.31,3.65
    

    【讨论】:

      【解决方案2】:

      这应该可以工作:sed -re 's/^([0-9][0-9])\/([0-9][0-9])\/[0-9][0-9]([0-9][0-9])(.*)$/\2\/\1\/\3\4/'

      它可以做得更小,但我做了它,所以它的作用会更明显(4组,只需切换月/日并删除一年的前两个字符)。

      提示:如果您不想cat 文件,您可以将in place 更改为sed -i。但要小心,如果您在其中输入错误的表达式,最终可能会破坏您的源文件。

      注意:假设如果年份指定为 4 位数字,则月/日是相反的。

      【讨论】:

      • 如何在我的文件上运行它并替换该文件或直接到一个新文件
      • @moadeep:您可以使用cat file | sed ... > outfile 或者您应该可以使用sed -ire ... FILE 进行就地编辑。
      • 小注:正则表达式中的最后一个(.*) 和最后一个\4 不是必需的,但也不会造成伤害。
      【解决方案3】:

      下面这个命令会做。

      注意:无论文件中有多少行。这只会更改最后 4 行。

      tail -r your_file| awk -F, 'NR<5{split($1,a,"/");$1=a[2]"/"a[1]"/"a[3];print}1'|tail -r
      

      好吧,我可以在不使用管道和使用单个 awk 语句的情况下找到一些方法,而且这个解决方案确实需要一个 tail 命令:

      awk -F, 'BEGIN{cmd="wc -l your_file";while (cmd|getline tmp);split(tmp,x)}x[1]-NR<=4{split($1,a,"/");$1=a[2]"/"a[1]"/"a[3];print}1' your_file
      

      【讨论】:

      • 这看起来像是一个不必要的复杂解决方案。我的意思是尾巴的两个叉子,您仍然需要指定要读取的行数吗?其次,-r 选项在我的tail coreutils v8.20 中不可用
      • 我无法使用 -r 选项。此外,我只想将 mm/dd/yyyy 格式的日期格式更改为 dd/mm/yy。此命令不会将 yyyy 更改为 yy 并为所有日期切换 dd 和 mm
      【解决方案4】:

      另一种解决方案:

      awk -F/ 'NR<4;NR>3{a=$1;$1=$2;$2=a; print $1"/"$2"/" substr($3,3,2) substr($3,5)}' file
      

      【讨论】:

        【解决方案5】:

        使用 awk:

        $ awk -F/ 'NR>3{x=$1;$1=$2;$2=x}1' OFS="/" file
        

        通过使用 / 作为分隔符,您需要做的就是交换第一个和第二个字段,这在此处使用临时变量完成。

        【讨论】:

        • 如果输入文件的行数超过8行就会失败
        • 想要交换每个日期的格式。我只想将 mm/dd/yyyy 格式的那些交换为 dd/mm/yy