Bash 函数查找最新的文件匹配模式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5885934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash function to find newest file matching pattern
提问by jlconlin
In Bash, I would like to create a function that returns the filename of the newest file that matches a certain pattern. For example, I have a directory of files like:
在 Bash 中,我想创建一个函数,该函数返回与特定模式匹配的最新文件的文件名。例如,我有一个文件目录,例如:
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
I want the newest file that starts with 'b2'. How do I do this in bash? I need to have this in my ~/.bash_profile
script.
我想要以“b2”开头的最新文件。我如何在 bash 中做到这一点?我需要在我的~/.bash_profile
脚本中有这个。
采纳答案by lesmana
The ls
command has a parameter -t
to sort by time. You can then grab the first (newest) with head -1
.
该ls
命令有一个-t
按时间排序的参数。然后,您可以使用head -1
.
ls -t b2* | head -1
But beware: Why you shouldn't parse the output of ls
但要注意:为什么你不应该解析 ls 的输出
My personal opinion: parsing ls
is only dangerous when the filenames can contain funny characters like spaces or newlines. If you can guarantee that the filenames will not contain funny characters then parsing ls
is quite safe.
我的个人观点:ls
只有当文件名包含有趣的字符(如空格或换行符)时,解析才会危险。如果你能保证文件名不包含有趣的字符,那么解析ls
是非常安全的。
If you are developing a script which is meant to be run by many people on many systems in many different situations then I very much do recommend to not parse ls
.
如果您正在开发一个脚本,该脚本旨在由许多人在许多不同情况下在许多系统上运行,那么我非常建议您不要解析ls
.
Here is how to do it "right": 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
回答by glenn Hymanman
Unusual filenames (such as a file containing the valid \n
character can wreak havoc with this kind of parsing. Here's a way to do it in Perl:
不寻常的文件名(例如包含有效\n
字符的文件可能会对这种解析造成严重破坏。这是在 Perl 中执行此操作的一种方法:
perl -le '@sorted = map {$_->[0]}
sort {$a->[1] <=> $b->[1]}
map {[$_, -M $_]}
@ARGV;
print $sorted[0]
' b2*
That's a Schwartzian transformused there.
这是那里使用的施瓦兹变换。
回答by pjh
This is a possible implementation of the required Bash function:
这是所需 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 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
}
It uses only Bash builtins, and should handle files whose names contain newlines or other unusual characters.
它仅使用 Bash 内置函数,并且应该处理名称包含换行符或其他不寻常字符的文件。
回答by Naufal
There is a much more efficient way of achieving this. Consider the following command:
有一种更有效的方法来实现这一点。考虑以下命令:
find . -cmin 1 -name "b2*"
This command finds the latest file produced exactly one minute ago with the wildcard search on "b2*". If you want files from the last two days then you'll be better off using the command below:
此命令使用通配符搜索“b2*”查找恰好一分钟前生成的最新文件。如果您想要过去两天的文件,那么最好使用以下命令:
find . -mtime 2 -name "b2*"
The "." represents the current directory. Hope this helps.
这 ”。” 代表当前目录。希望这可以帮助。
回答by Boris Brodski
The combination of find
and ls
works well for
的组合find
,并ls
可以很好地用于
- filenames without newlines
- not very large amount of files
- not very long filenames
- 没有换行符的文件名
- 文件量不是很大
- 不是很长的文件名
The solution:
解决方案:
find . -name "my-pattern" -print0 |
xargs -r -0 ls -1 -t |
head -1
Let's break it down:
让我们分解一下:
With find
we can match all interesting files like this:
随着find
我们可以匹配所有有趣的文件是这样的:
find . -name "my-pattern" ...
then using -print0
we can pass all filenames safely to the ls
like this:
然后使用-print0
我们可以安全地将所有文件名传递给ls
这样的:
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
additional find
search parameters and patterns can be added here
find
可以在此处添加其他搜索参数和模式
find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
will sort files by modification time (newest first) and print it one at a line. You can use -c
to sort by creation time. Note: this will break with filenames containing newlines.
ls -t
将按修改时间(最新的在前)对文件进行排序,并在一行中打印一个。您可以使用-c
按创建时间排序。注意:这将打破包含换行符的文件名。
Finally head -1
gets us the first file in the sorted list.
最后head -1
得到我们排序列表中的第一个文件。
Note:xargs
use system limits to the size of the argument list. If this size exceeds, xargs
will call ls
multiple times. This will break the sorting and probably also the final output. Run
注意:xargs
使用系统限制参数列表的大小。如果超过这个大小,xargs
将调用ls
多次。这将破坏排序,也可能破坏最终输出。跑
xargs --show-limits
to check the limits on you system.
检查您系统的限制。
Note 2:use find . -maxdepth 1 -name "my-pattern" -print0
if you don't want to search files through subfolders.
注2:使用find . -maxdepth 1 -name "my-pattern" -print0
如果你不想通过子文件夹进行搜索文件。
Note 3:As pointed out by @starfry - -r
argument for xargs
is preventing the call of ls -1 -t
, if no files were matched by the find
. Thank you for the suggesion.
注3:正如指出的@starfry --r
论据xargs
阻止的呼叫ls -1 -t
,如果没有文件被匹配find
。谢谢你的建议。
回答by dawg
You can use stat
with a file glob and a decorate-sort-undecorate with the file time added on the front:
您可以使用stat
文件 glob 和decorate-sort-undecorate,并在前面添加文件时间:
$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-
回答by Eric Leschinski
Dark magic function incantation for those who want the find ... xargs ... head ...
solution above, but in easy to use function form so you don't have to think:
暗魔法函数咒语适合那些想要上述find ... xargs ... head ...
解决方案的人,但以易于使用的函数形式让您不必考虑:
#define the function
find_newest_file_matching_pattern_under_directory(){
echo $(find -name -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
Prints:
印刷:
file2.txt
Which is:
这是:
The filename with the oldest modified timestamp of the file under the given directory matching the given pattern.
具有与给定模式匹配的给定目录下文件的最旧修改时间戳的文件名。
回答by l3x
Use the find command.
使用查找命令。
Assuming you're using Bash 4.2+, use -printf '%T+ %p\n'
for file timestamp value.
假设您使用的是 Bash 4.2+,请使用-printf '%T+ %p\n'
文件时间戳值。
find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
Example:
例子:
find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
For a more useful script, see the find-latestscript here: https://github.com/l3x/helpers
有关更有用的脚本,请参阅此处的find-latest脚本:https: //github.com/l3x/helpers