Bash函数来查找最新的文件匹配模式

在Bash中,我想创build一个函数,返回匹配特定模式的最新文件的文件名。 例如,我有一个像这样的文件的目录:

Directory/ a1.1_5_1 a1.2_1_4 b2.1_0 b2.2_3_4 b2.3_2_0 

我想要以“b2”开头的最新文件。 我如何在bash中做到这一点? 我需要在我的~/.bash_profile脚本中有这个。

Solutions Collecting From Web of "Bash函数来查找最新的文件匹配模式"

ls命令有一个参数-t按时间排序。 然后你可以抓住head -1 (最新)。

 ls -t b2* | head -1 

但要小心: 为什么你不应该分析ls的输出

我的个人意见:解析ls只有当文件名可以包含空格或换行符等有趣的字符时才是危险的。 如果你可以保证文件名不包含有趣的字符,那么解析ls是相当安全的。

如果你正在开发一个脚本,在许多不同的情况下,许多系统上运行的脚本,我非常推荐不要分析ls

这里是如何做到“正确”: 我怎样才能找到目录中的最新(最新,最早,最旧)文件?

 unset -v latest for file in "$dir"/*; do [[ $file -nt $latest ]] && latest=$file done 

这是所需的Bash函数的一个可能的实现:

 # Print the newest file, if any, matching the given pattern # Example usage: # newest_matching_file 'b2*' # WARNING: Files whose names begin with a dot will not be checked function newest_matching_file { # Use ${1-} instead of $1 in case 'nounset' is set local -r glob_pattern=${1-} if (( $# != 1 )) ; then echo 'usage: newest_matching_file GLOB_PATTERN' >&2 return 1 fi # To avoid printing garbage if no files match the pattern, set # 'nullglob' if necessary local -i need_to_unset_nullglob=0 if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then shopt -s nullglob need_to_unset_nullglob=1 fi newest_file= for file in $glob_pattern ; do [[ -z $newest_file || $file -nt $newest_file ]] \ && newest_file=$file done # To avoid unexpected behaviour elsewhere, unset nullglob if it was # set by this function (( need_to_unset_nullglob )) && shopt -u nullglob # Use printf instead of echo in case the file name begins with '-' [[ -n $newest_file ]] && printf '%s\n' "$newest_file" return 0 } 

它只使用Bash内建函数,并且应该处理名称中包含换行符或其他不常用字符的文件。

不寻常的文件名(例如包含有效的\n字符的文件可能会对这种解析产生巨大的影响,下面是在Perl中执行的一种方法:

 perl -le '@sorted = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, -M $_]} @ARGV; print $sorted[0] ' b2* 

那是在那里使用的Schwartzian变换 。

有一个更有效的方法来实现这一点。 考虑下面的命令:

 find . -cmin 1 -name "b2*" 

这个命令找到刚刚一分钟前产生的最新文件,在“b2 *”上进行通配符搜索。 如果你想从最近两天的文件,那么你最好使用下面的命令:

 find . -mtime 2 -name "b2*" 

“。” 代表当前目录。 希望这可以帮助。

findls的组合很适合

  • 没有换行符的文件名
  • 文件数量不是很大
  • 不是很长的文件名

解决方案:

 find . -name "my-pattern" ... -print | xargs -0 ls -1 -t | head -1 

让我们来分解一下:

find我们可以匹配所有有趣的文件,如:

 find . -name "my-pattern" ... 

然后使用-print0我们可以安全地将所有文件名传递给ls如下所示:

 find . -name "my-pattern" ... -print0 | xargs -0 ls -1 -t 

ls -t将按修改时间对文件进行排序(最新的第一个)并将其打印一行。 您可以使用-c按创建时间进行排序。 注意 :这将打破包含换行符的文件名。

最后, head -1得到我们排序列表中的第一个文件。

注意: xargs使用系统限制参数列表的大小。 如果这个大小超过, xargs会多次调用ls 。 这将打破排序,也可能是最终的输出。 跑

 xargs --show-limits 

检查您的系统的限制。