识别单个unix目录中文本文件中的模式



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

输入:

$ls

a_20171007_001.txt
a_201710007_002.txt
b_20171007_0001.txt
20180101_001.txt

预期输出:

a_20171007_002.txt
b_20171007_001.txt

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

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


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

例如,输入:

ab_bc_所有_20171008_001.xt

bc_cd_ad_所有_20171008_001.xt

ab_bc_所有_20171008_002.txt

ad_dc_cd_ed_所有_20180101_001.xt

ae_bc_zx_ed_ac_所有_20170918_001.xt

输出:

bc_cd_ad_all_20171008_001.xt

ab_bc_all_20171008_002.txt

ae_bc_zx_ed_ac_all_20170918_001.xt

在上面的情况下,只有"all">之后的模式才会显示日期字段。你能就上述情况提出建议吗。。

提前谢谢。

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";
}
}

一个简单的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,并且前缀(例如a、b等)不存在于数组file中,则将其存储在file数组中(例如file['a']=a_20171007_001.txt),否则将不存储,在本例中,将直接拒绝c_20180101_001.txt

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

你能试试下面的内容吗?如果这对你有帮助,请告诉我。

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

GNUAwk静态文件名格式<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

这个只在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
$ ls -1r | awk -v today="$(date +%Y%m%d)" -F'_' '($2 <= today) && !seen[$1,$2]++'
b_20171007_001.txt
a_20171007_002.txt

最新更新