我可以从 bash glob 中只选择一个结果吗?

Pur*_*ret 14 bash wildcards glob

我正在尝试编写一个脚本来自动对输出进行一些报告。日志文件(目前,将来会“标准化”)存储在这种路径结构中:

/<root_path>/<process_one_path>/logs/<time_date_stamp>/<specific_log_file>

/<root_path>/<process_two_path>/logs/<different_time_date_stamp>/<specific_log_file>

路径的每一部分都是已知的,除了时间日期戳,它们总是文件夹中的最新的。

如果我尝试使用通配符代替时间日期戳,我会得到多个结果,例如:

> ls /<root_path>/<process_two_path>/logs/* [tab]
20130102-175103
20130118-090859
20130305-213506
Run Code Online (Sandbox Code Playgroud)

我只希望它返回最新的一个,这可以用 Bash 实现吗?

注意(我没有 zsh,虽然听起来很可爱,但我怀疑我们是否会在工作中使用它)

Sté*_*las 10

POSIXly:

 set -- /<root_path>/<process_two_path>/logs/*
 shift "$(($# - 1))"
 printf '%s\n' "$1"
Run Code Online (Sandbox Code Playgroud)

既然你提到zsh

 print -r /<root_path>/<process_two_path>/logs/*([-1])
Run Code Online (Sandbox Code Playgroud)


phe*_*mer 9

以下在 bash 4.2 中有效:

list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[-1]}"
Run Code Online (Sandbox Code Playgroud)

如果您的 bash 是旧版本:

list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[${#list[@]}-1]}"
Run Code Online (Sandbox Code Playgroud)


les*_*ana 5

您可以(错误地)使用 for 循环。像这样:

for filename in <logdir>/*; do :; done; echo "$filename"
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为循环变量filename在循环终止后仍然包含最后一个值。还因为 bash 会按字母顺序进行全局扩展。阅读bash 手册以获取更多信息。请注意,这取决于LC_COLLATE

这可能不是最有效的,因为 bash 仍然必须循环所有文件而不执行任何操作。但对于合理数量的文件来说,它应该仍然足够快。如果它不再足够快,则文件数量变得不合理,您应该考虑采用不同的方法。

如果您想要具有最旧时间戳的文件名(第一个排序的),您可以这样做:

for filename in <logdir>/*; do echo "$filename"; break; done
Run Code Online (Sandbox Code Playgroud)

或这个

for filename in <logdir>/*; do break; done; echo "$filename"
Run Code Online (Sandbox Code Playgroud)

这实际上是相同的(打印第一个文件名),但根据您的代码和样式偏好,您可能更喜欢其中一个。