识别单个unix目录中

时间:2017-10-07 17:13:33

标签: linux shell unix awk sed

如果我想在一个目录中识别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不应出现输出)
  3. 有关如何在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'之后的日期字段出现。 你可以在上面的案例中建议..

    提前致谢。

6 个答案:

答案 0 :(得分: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";
    }
}

答案 1 :(得分:1)

一个简单的 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

<强>解释

date

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

在迭代记录/文件名时,如果文件名中的日期$2小于或等于current date且前缀(例如a,b等)不存在在数组file中,然后将其存储在file数组中,例如。 file['a']=a_20171007_001.txt否则它将无法存储,在此示例中,c_20180101_001.txt将被直接拒绝。

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

答案 2 :(得分:0)

请您试着跟随并告诉我这是否对您有帮助。

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
}
}'

答案 3 :(得分:0)

GNU Awk 静态文件名格式<prefix>_<date>_<version>.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

答案 4 :(得分:0)

这个只在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

答案 5 :(得分:-1)

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