Bash函数来寻找最新的文件匹配模式
在Bash中,我想创建一个函数,返回匹配特定模式的最新文件的文件名。例如,我有一个文件目录: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
脚本中有这个。
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
对其他人的注意事项:如果您正在为目录执行此操作,则需要向ls添加-d选项,例如'ls -td
[解析LS](http://mywiki.wooledge.org/ParsingLs)链接表示不这样做,并建议在[BashFAQ 99](http://mywiki.wooledge.org/BashFAQ/099)。我正在寻找一个1-liner,而不是防弹包含在脚本中,所以我会继续像@lesmana那样不安分地解析ls。 – Eponymous 2014-06-05 00:07:37
@同名:如果你正在寻找一个没有使用脆弱的'ls','printf'%s \ n“b2 * |头-1'将为你做。 – 2016-12-01 04:27:02
不寻常的文件名(如含有有效\n
角色可以肆虐用这种分析的一个文件,这里有一个办法做到这一点的的Perl:
perl -le '@sorted = map {$_->[0]}
sort {$a->[1] <=> $b->[1]}
map {[$_, -M $_]}
@ARGV;
print $sorted[0]
' b2*
这是一个Schwartzian transform使用有
可能schwartz与你同在! – 2016-06-24 17:45:57
这个答案可能工作,但我不会信任它,因为糟糕的文档。 – 2016-12-04 12:56:27
糟糕的文档?它带有一个wikipage ... – 2017-04-12 23:20:47
这是可能实现的。需要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内建函数,并且应该处理名称中包含换行符或其他不寻常字符的文件。
你可以使用'nullglob_shopt = $(shopt -p nullglob)',然后''nullglob''把'nullglob'放回原来的状态。 – 2014-11-05 21:14:11
@gniourf_gniourf使用$(shopt -p nullglob)的建议是一个很好的建议。我通常尽量避免使用命令替换('$()'或反引号),因为它很慢,特别是在Cygwin下,即使命令只使用内置函数。另外,运行命令的子shell上下文有时会导致它们以意想不到的方式运行。我也尝试避免在变量中存储命令(比如'nullglob_shopt'),因为如果你得到的变量值不对,会发生很糟糕的事情。 – pjh 2014-11-06 20:25:55
我很欣赏对细节的关注,如果忽略了这些细节,可能会导致模糊的失败。谢谢! – 2016-07-31 18:32:07
有一个更有效的方法来实现这一点。请看下面的命令:
find . -cmin 1 -name "b2*"
这个命令在与“B2 *”通配符搜索产生恰好一分钟前的最新文件。如果你想从最近两天的文件,那么你会更好使用以下命令:“”
find . -mtime 2 -name "b2*"
的代表当前目录。 希望这有助于。
的find
和ls
行之有效的
- 文件名不带换行的组合
- 不是很大量文件的
- 不是很长文件名
解决办法:
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
检查系统的限制。
有关更多答案提示,请参阅http://superuser.com/questions/294161/unix-linux-find-and-sort-by-date-modified。排序是获取最新文件的关键步骤 – 2016-12-04 13:06:33