【问题标题】:Identify pattern in text files in a single unix directory识别单个 unix 目录中文本文件中的模式
【发布时间】:2018-03-19 06:38:24
【问题描述】:

如果我想在一个单一目录中识别 Unix 中的模式,我可以知道哪个 unix 实用程序会有所帮助(如 awk)

输入:

$ ls

a_20171007_001.txt
a_20171007_002.txt
b_20171007_001.txt
c_20180101_001.txt

期待输出:

a_20171007_002.txt
b_20171007_001.txt

  1. 无论文件创建时间如何,输出都应根据文件名返回最新版本的文件
  2. 输出文件不应包含未来日期文件(例如,当前日期:20171008,因此 20180101 不应出现在输出中)

关于如何在 unix(awk 或 sed)中轻松实现这一点的任何建议


非常感谢您提供的所有解决方案。但不幸的是,如果文件名不遵循任何模式,则无济于事。

例如,输入:

ab_bc_全部_20171008_001.txt

bc_cd_ad_全部_20171008_001.txt

ab_bc_全部_20171008_002.txt

ad_dc_cd_ed_全部_20180101_001.txt

ae_bc_zx_ed_ac_全部_20170918_001.txt

输出:

bc_cd_ad_all_20171008_001.txt

ab_bc_all_20171008_002.txt

ae_bc_zx_ed_ac_all_20170918_001.txt

在上述情况下,只有在 'all' 之后出现日期字段的模式。 您能否在上述情况下提出建议..

提前致谢。

【问题讨论】:

  • 你的版本号可以有4位数字吗?如果是,它们是否仅在 999 之后开始?例如。 a_20171007_999.txt a_20171007_1000.txt ?

标签: linux shell unix awk sed


【解决方案1】:

Perl 中的类似内容:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

use Time::Piece;

my $today = localtime->ymd("");
my %latest;
for my $file (glob '*.txt') {
    my ($id, $date, $num) = split /[_.]/, $file;
    $latest{$id}{$date} = $num
        if $date <= $today
        && (! exists $latest{$id}
            || ! exists $latest{$id}{$date}
            || $num > $latest{$id}{$date});
}
for my $id (keys %latest) {
    for my $date (keys %{ $latest{$id} }) {
        say "$id\_$date\_$latest{$id}{$date}.txt";
    }
}

【讨论】:

    【解决方案2】:

    一个简单的awk解决方案

    $ awk -F_ -vdate=`date +%Y%m%d` ' !($1 in file) && $2<=date {file[$1]=$0} ($1 in file){if($0>=file[$1]){file[$1]=$0}} END{ for(i in file)print file[i] }' f1
    a_20171007_002.txt
    b_20171007_001.txt
    

    说明:

    yyyymmdd 格式将当前日期存储在date 变量中

    在遍历记录/文件名时,如果文件名中的日期,即$2 小于或等于current date,并且数组file 中不存在前缀(例如a、b 等),则将其存储在file 数组中,例如。 file['a']=a_20171007_001.txt 否则它不会被存储,在这个例子中 c_20180101_001.txt 将被直接拒绝。

    对于下一条记录,如果prefix$1 存在于数组file 中,则检查整个记录是否大于现有记录(按字典顺序)。如果是,覆盖file数组中的记录。

    【讨论】:

      【解决方案3】:

      您能否尝试关注一下,如果这对您有帮助,请告诉我。

      ls -ltr *.txt | awk -v date=$(date +%Y) -F"_" 'prev != $1 && val && date_val<=date{print val} {prev=$1;val=$0;date_val=substr($2,1,4)} END{if(date_val<=date){print val}}'
      

      现在也添加一种可读性更好的解决方案。

      ls -ltr *.txt |  awk -v date=$(date +%Y) -F"_" '
      prev != $1 && val && date_val<=date{
        print val
      }
      {
      prev=$1;
      val=$0
      date_val=substr($2,1,4)
      }
      END{
      if(date_val<=date){
       print val
      }
      }'
      

      【讨论】:

        【解决方案4】:

        GNU Awk 解决静态文件名格式&lt;prefix&gt;_&lt;date&gt;_&lt;version&gt;.txt:

        示例ls -1 输出(扩展):

        a_20171007_001.txt
        a_20171007_002.txt
        b_20171007_001.txt
        c_20180101_001.txt
        a_20171007_0010.txt
        b_20171007_004.txt
        

        ls -1 | awk -F'[_.]' '{ k=$1"_"$2 }{ if (a[k]<$3) a[k]=$3 }
                END{ 
                    for (i in a) { 
                        split(substr(i, index(i,"_")+1), b, "");
                        ts=mktime(sprintf("%d %d %d 00 00 00",b[1]b[2]b[3]b[4],b[5]b[6],b[7]b[8]));
                        if (systime() >= ts) print i"_"a[i]".txt" 
                    } 
                }'
        

        输出:

        b_20171007_004.txt
        a_20171007_0010.txt
        

        【讨论】:

          【解决方案5】:

          这个只在shell中可以(破折号)

          d=$(date +%Y%m%d)
          ls -1r *_*_*.txt|while IFS='_' read w x y
          do
           [ "$x" -le "$d" ] && [ "$v" != "$w$x" ] && { echo "$w"_"$x"_"$y";v="$w$x";}
          done
          

          规格变化??? 试试这个

          d=$(date +%Y%m%d)
          ls -1r *_*_*.txt|while read l
          do
           b="${l%_*_*}"
           a="${l#$b*_}"
           c="${a%_*}"
           [ "$c" -le "$d" ] && [ "$v" != "$b$c" ] && { echo "$l";v="$b$c";}
          done
          

          【讨论】:

            【解决方案6】:
            $ ls -1r | awk -v today="$(date +%Y%m%d)" -F'_' '($2 <= today) && !seen[$1,$2]++'
            b_20171007_001.txt
            a_20171007_002.txt
            

            【讨论】:

            • 你能解释一下为什么这解决了问题,而不仅仅是发布一些代码吗?这将更有帮助,尤其是对于初学者,谢谢。
            • 不,它非常清楚、明显和简短,因此任何不理解它的人都会从浏览手册页中受益更多。我假设您要求对这个简短、琐碎的答案进行解释,而不是在此页面上要求解释更长更复杂的答案,因为考虑到它的简短程度,一个工具将其标记为可能低质量。如果您不知道该域,请不要发表评论,继续前进。
            • 紧凑的代码很好而且很有帮助。但解释是必不可少的,您也可以链接或引用一些手册页。或者对命令的作用给出一个非常简短的解释。这是您的决定,但这将提高答案的质量,当然还可以防止低质量的标记。
            猜你喜欢
            • 1970-01-01
            • 2019-02-01
            • 2014-02-10
            • 2012-09-21
            • 1970-01-01
            • 2016-11-04
            • 1970-01-01
            • 1970-01-01
            • 2022-11-28
            相关资源
            最近更新 更多