在Bash中,我想创建一个函数,它返回与某个模式匹配的最新文件的文件名。例如,我有一个文件目录,如:
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
我想要以'b2'开头的最新文件。我怎么在bash中这样做?我需要在我的~/.bash_profile
脚本中使用此功能。
答案 0 :(得分:180)
ls
命令有一个参数-t
可按时间排序。然后,您可以使用head -1
抓住第一个(最新的)。
ls -t b2* | head -1
但要注意:Why you shouldn't parse the output of ls
我的个人观点:解析ls
只有在文件名可以包含空格或换行等有趣字符时才会有危险。如果您可以保证文件名不包含有趣的字符,那么解析ls
是非常安全的。
如果您正在开发一个脚本,该脚本在许多不同情况下由许多系统上的许多人运行,那么我非常建议不要解析ls
。
以下是如何“正确”:How can I find the latest (newest, earliest, oldest) file in a directory?
unset -v latest
for file in "$dir"/*; do
[[ $file -nt $latest ]] && latest=$file
done
答案 1 :(得分:10)
find
和ls
的组合适用于
解决方案:
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
ls -t
将按修改时间(最新的第一个)对文件进行排序,并在一行中打印一个。您可以使用-c
按创建时间排序。 注意:这会破坏包含换行符的文件名。
最后head -1
获取排序列表中的第一个文件。
注意: xargs
对参数列表的大小使用系统限制。如果此尺寸超出,xargs
将多次调用ls
。这将打破排序,也可能打破最终输出。运行
xargs --show-limits
检查系统的限制。
注2:如果您不想通过子文件夹搜索文件,请使用find . -maxdepth 1 -name "my-pattern" -print0
。
注3:正如@starfry所指出的那样 - -r
的{{1}}参数阻止xargs
的调用,如果没有匹配的文件ls -1 -t
。谢谢你的建议。
答案 2 :(得分:5)
这是所需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内置函数,并且应该处理名称中包含换行符或其他异常字符的文件。
答案 3 :(得分:2)
不寻常的文件名(例如包含有效\n
字符的文件可能会对这种解析造成严重破坏。以下是在Perl中执行此操作的方法:
perl -le '@sorted = map {$_->[0]}
sort {$a->[1] <=> $b->[1]}
map {[$_, -M $_]}
@ARGV;
print $sorted[0]
' b2*
那是Schwartzian transform那里使用的。
答案 4 :(得分:2)
使用find命令。
假设您使用的是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
答案 5 :(得分:1)
有一种更有效的方法来实现这一目标。请考虑以下命令:
find . -cmin 1 -name "b2*"
此命令通过“b2 *”上的通配符搜索找到一分钟前生成的最新文件。如果您想要过去两天的文件,那么最好使用以下命令:
find . -mtime 2 -name "b2*"
“。”代表当前目录。 希望这会有所帮助。
答案 6 :(得分:0)
您可以将stat
与文件文件一起使用,并将decorate-sort-undecorate与前面添加的文件时间一起使用:
$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-
答案 7 :(得分:0)
暗黑魔法功能咒语,适用于那些希望使用上述find ... xargs ... head ...
解决方案但使用简单易用的功能形式的人,因此您无需考虑:
#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
哪个是
:在给定目录下,文件的修改时间戳最旧的文件名与给定模式匹配。
答案 8 :(得分:0)