我正在尝试编写一个脚本来自动执行一些输出报告。日志文件(目前,将来正在“标准化”)存储在这种路径结构中:
/<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
我只希望它返回最新的一个,这对于 Bash 来说可能吗?
注意(我没有 zsh,虽然听起来很可爱,但我怀疑我们在工作中是否能得到它)
答案1
以下内容在 bash 4.2 中有效:
list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[-1]}"
如果您的 bash 是旧版本:
list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[${#list[@]}-1]}"
答案2
POSIXly:
set -- /<root_path>/<process_two_path>/logs/*
shift "$(($# - 1))"
printf '%s\n' "$1"
既然你提到zsh
:
print -r /<root_path>/<process_two_path>/logs/*([-1])
如果 中没有非隐藏文件/<root_path>/<process_two_path>/logs
,则 POSIX 文件将输出一个文字,/<root_path>/<process_two_path>/logs/*
同时zsh
将返回一个错误并中止 shell 进程,就像它是语法错误一样。你总是可以处理中的错误always
堵塞,或使用N
(对于nullglob
)全局限定符并亲自处理案件。
1 如果 glob 位于外部命令的参数中(不是print
因为它是 zsh 内置命令),则只会退出运行该命令的进程,因此它只会显示为取消该命令。在交互式 shell 中,它返回到提示符而不是退出 shell,与其他语法错误相同。
答案3
您可以(错误地)使用 for 循环。像这样:
for filename in <logdir>/*; do :; done; echo "$filename"
这是有效的,因为循环变量filename
在循环终止后仍然包含最后一个值。还因为 bash 会按字母顺序进行全局扩展。阅读bash手册了解更多信息。请注意,这取决于LC_COLLATE。
这可能不是最有效的,因为 bash 仍然必须循环所有文件而不执行任何操作。但对于合理数量的文件来说,它应该仍然足够快。如果它不再足够快,则文件数量变得不合理,您应该考虑采用不同的方法。
如果您想要具有最旧时间戳的文件名(第一个排序的),您可以这样做:
for filename in <logdir>/*; do echo "$filename"; break; done
或这个
for filename in <logdir>/*; do break; done; echo "$filename"
这实际上是相同的(打印第一个文件名),但根据您的代码和样式偏好,您可能更喜欢其中一个。
答案4
ls -tr | tail -1
应该做到这一点。