bash从列表中选择最新版本的文件

时间:2014-01-12 21:19:04

标签: linux bash awk

我在目录中有以下“结构”文件名:

ABC_abcabc_ver01.txt
ABC_abcabc_ver02.txt
ABC_abcabc_ver04.txt
DEF_defdef_ver01.txt
GHI_ghighi_ver01.txt
GHI_ghighi_ver08.txt

我想获得的是仅限最新版本的列表(文件名称中的最后一位数字),即

ABC_abcabc_ver04.txt
DEF_defdef_ver01.txt
GHI_ghighi_ver08.txt

请注意,数字不一定是连续的,并非所有文件都有多个版本。为简单起见,可以假设最大可能的版本是'09',但是有一个更通用的解决方案会很酷。我知道awk(没有sed),所以我很有可能理解基于awk的想法。欢迎任何帮助。

3 个答案:

答案 0 :(得分:3)

你可以ls -1 or find...并管道:

awk -F '_ver' '{a[$1]=$2>a[$1]?$2:a[$1]}END{for(x in a)print x FS a[x]}'

使用您的数据作为标准输入进行测试:

kent$  awk -F '_ver' '{a[$1]=$2>a[$1]?$2:a[$1]}END{for(x in a)print x FS a[x]}' <<<"ABC_abcabc_ver01.txt
ABC_abcabc_ver02.txt
ABC_abcabc_ver04.txt
DEF_defdef_ver01.txt
GHI_ghighi_ver01.txt
GHI_ghighi_ver08.txt"

输出:

GHI_ghighi_ver08.txt
ABC_abcabc_ver04.txt
DEF_defdef_ver01.txt

修改

添加“评论”,OP询问:

awk -F '_ver'                   #use "_ver" as field separator
'{a[$1]=$2>a[$1]?$2:a[$1]}      #build an arry(hashtable),key:1st field, value:2nd filed (I guess you understood a=b>a?b:a)
END{for(x in a)print x FS a[x]}'#at the end, print all elements from the array

答案 1 :(得分:2)

有一种方法可以用纯粹的bash来做到这一点:

#!/bin/bash

shopt -s extglob
declare -A filesDict
export LC_COLLATE=C # so that * expansion order is always the same

for curFile in *; do
    extension=${curFile#*.}
    filename=${curFile%%+([[:digit:]]).*} # get rid of the version number and extension
    if [[ $curFile == "$filename"+([[:digit:]])".$extension" ]]; then # if doing it backwards results in the same filename. We do that to ignore other random files that might appear in a directory
        filesDict["$filename.$extension"]=$curFile # add or overwrite value in the dictionary. Overwriting is always safe because files with the biggest version number will always come last (assuming that they're zero-padded)
    fi
done

for curKey in "${!filesDict[@]}"
do
    echo "File: $curKey    Last version: ${filesDict[$curKey]}"
done

此脚本依赖于使用字母顺序展开*的bash行为。我不确定所有语言环境是否都适合数字,所以我强制LC_COLLATE=C只是为了确定。

现在,如果你忽略了这个脚本太棘手的事实,你会发现它实际上是一个非常好的解决方案,因为它可以处理你可以拥有的任何文件名(甚至那些在名称中有换行符的文件名)。 / p>

当您拥有相同的文件名但具有不同的扩展名(例如test01.txttest01.tar.gz时,它也将处理这种情况,这些将被视为不同的文件)

它将忽略没有扩展名或没有版本号的文件。如果要包含没有版本号的文件,只需将+([[:digit:]])更改为*([[:digit:]])(请注意,脚本中有两次出现)。您也可以删除点以包含没有扩展名的文件名,但这是一个完全不同的故事。

答案 2 :(得分:0)

sort -t _ -k1,1 -k2,2 -k 3.4nr file|awk -F _ '!a[$1 FS $2]++'

ABC_abcabc_ver04.txt
DEF_defdef_ver01.txt
GHI_ghighi_ver08.txt

<强>解释

sort命令将按预期对文件进行排序:

ABC_abcabc_ver04.txt
ABC_abcabc_ver02.txt
ABC_abcabc_ver01.txt
DEF_defdef_ver01.txt
GHI_ghighi_ver08.txt
GHI_ghighi_ver01.txt

awk命令始终采用最新的一个(第一个)。