如果我想在一个目录中识别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
- 无论文件创建时间如何,输出都应根据文件名返回文件的最新版本
- 输出文件不应该有未来日期的文件(例如,当前日期: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