繁体   English   中英

Bash function 找到最新的文件匹配模式

[英]Bash function to find newest file matching pattern

在 Bash 中,我想创建一个 function,它返回与特定模式匹配的最新文件的文件名。 例如,我有一个文件目录,例如:

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

我想要以“b2”开头的最新文件。 如何在 bash 中执行此操作? 我需要在我的~/.bash_profile脚本中有这个。

ls命令有一个参数-t用于按时间排序。 然后,您可以使用head -1获取第一个(最新的)。

ls -t b2* | head -1

但要注意:为什么你不应该解析 ls 的 output

我个人的观点:只有当文件名可以包含有趣的字符(如空格或换行符)时,解析ls才是危险的。 如果您可以保证文件名不会包含有趣的字符,那么解析ls是非常安全的。

如果您正在开发一个脚本,该脚本旨在由许多人在许多不同情况下在许多系统上运行,那么我非常建议不要解析ls

以下是“正确”的做法:如何在目录中找到最新(最新、最早、最旧)的文件?

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

findls的组合适用于

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

解决方案:

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

让我们分解一下:

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

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

然后使用-print0我们可以像这样安全地将所有文件名传递给ls

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

可以在此处添加其他find搜索参数和模式

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

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

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

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

xargs  --show-limits

检查您系统的限制。

注2:使用find. -maxdepth 1 -name "my-pattern" -print0 find. -maxdepth 1 -name "my-pattern" -print0如果您不想通过子文件夹搜索文件。

注 3:正如@starfry 所指出的 - -r参数xargs正在阻止调用ls -1 -t ,如果没有文件与find匹配。 谢谢你的建议。

这是所需 Bash function 的可能实现:

# 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*

这是那里使用的施瓦茨变换

您可以将stat与文件 glob 和 decorate-sort-undecorate 一起使用,并在前面添加文件时间:

$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-

黑暗魔法 function 咒语适用于那些想要find... xargs... head...解决方案的人,但易于使用 function 形式,因此您不必思考:

#define the function
find_newest_file_matching_pattern_under_directory(){
    echo $(find $1 -name $2 -print0 | xargs -0 ls -1 -t | head -1)
}

#setup:
#mkdir /tmp/files_to_move
#cd /tmp/files_to_move
#touch file1.txt
#touch file2.txt

#invoke the function:
newest_file=$( find_newest_file_matching_pattern_under_directory /tmp/files_to_move/ bc* )
echo $newest_file

印刷:

file2.txt

这是:

与给定模式匹配的给定目录下文件的最早修改时间戳的文件名。

使用查找命令。

假设您使用的是 Bash 4.2+,请使用-printf '%T+ %p\n'作为文件时间戳值。

find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2

例子:

find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2

有关更有用的脚本,请参阅此处的find-latest脚本: https://github.com/l3x/helpers

对于谷歌员工:

ls -t | head -1

  • -t按上次修改日期时间排序
  • head -1只返回第一个结果

不要在生产中使用

有一种更有效的方法可以实现这一点。 考虑以下命令:

find . -cmin 1 -name "b2*"

此命令使用通配符搜索“b2*”查找恰好在一分钟前生成的最新文件。 如果您想要最近两天的文件,那么最好使用以下命令:

find . -mtime 2 -name "b2*"

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM