【发布时间】:2012-03-05 18:23:44
【问题描述】:
我想在一个目录中找到最新的子目录并将结果保存到bash中的变量中。
类似这样的:
ls -t /backups | head -1 > $BACKUPDIR
谁能帮忙?
【问题讨论】:
标签: bash
我想在一个目录中找到最新的子目录并将结果保存到bash中的变量中。
类似这样的:
ls -t /backups | head -1 > $BACKUPDIR
谁能帮忙?
【问题讨论】:
标签: bash
BACKUPDIR=$(ls -td /backups/*/ | head -1)
$(...) 在子shell 中评估语句并返回输出。
【讨论】:
ls。有关处理ls 的输出的危险的详细说明,请参阅ParsingLs - Greg's Wiki。
上面的解决方案没有考虑到文件被写入和从目录中删除导致返回上层目录而不是最新的子目录。
另一个问题是这个解决方案假定目录只包含其他目录而不是正在写入的文件。
假设我创建了一个名为“test.txt”的文件,然后再次运行此命令:
echo "test" > test.txt
ls -t /backups | head -1
test.txt
结果是出现了 test.txt 而不是最后修改的目录。
建议的解决方案“有效”,但仅适用于最佳情况。
假设您最多有 1 个目录深度,更好的解决方案是使用:
find /backups/* -type d -prune -exec ls -d {} \; |tail -1
只需将“/backups/”部分换成您的实际路径即可。
如果你想避免在 bash 脚本中显示绝对路径,你总是可以使用这样的:
LOCALPATH=/backups
DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1)
【讨论】:
find /backups/* -type d -prune -exec ... 在 shell 扩展 /backups/* 时按照目录的生成顺序处理目录。顺序由名称决定,而不是时间戳。最后列出的目录通常不是是最新的。
嗯,我认为这个解决方案是最有效的:
path="/my/dir/structure/*"
backupdir=$(find $path -type d -prune | tail -n 1)
解释为什么这会好一点:
我们不需要子 shell(除了用于将结果输入 bash 变量的子 shell)。
我们不需要在find 命令末尾添加一个无用的-exec ls -d,它已经打印了目录列表。
我们可以很容易地改变它,例如排除某些模式。例如,如果您想要第二个最新目录,因为备份文件首先写入同一路径中的 tmp 目录:
backupdir=$(find $path -type -d -prune -not -name "*temp_dir" | tail -n 1)
【讨论】:
这是一个纯 Bash 解决方案:
topdir=/backups
BACKUPDIR=
# Handle subdirectories beginning with '.', and empty $topdir
shopt -s dotglob nullglob
for file in "$topdir"/* ; do
[[ -L $file || ! -d $file ]] && continue
[[ -z $BACKUPDIR || $file -nt $BACKUPDIR ]] && BACKUPDIR=$file
done
printf 'BACKUPDIR=%q\n' "$BACKUPDIR"
它会跳过符号链接,包括指向目录的符号链接,这可能是也可能不是正确的做法。它跳过其他非目录。它处理名称中包含任何字符的目录,包括换行符和前导点。
【讨论】:
有一个简单的解决方案,只使用ls:
BACKUPDIR=$(ls -td /backups/*/ | head -1)
-t 按时间排序(最新优先)-d 仅列出此文件夹中的项目*/ 只列出目录head -1 返回第一项在找到Listing only directories using ls in bash: An examination 之前,我不知道*/。
【讨论】:
你的“像这样的东西”几乎很受欢迎:
BACKUPDIR=$(ls -t ./backups | head -1)
把你写的和我学到的结合起来也解决了我的问题。感谢您提出这个问题。
注意:我在 Windows 环境中的 GitBash 中运行上面的行,文件名为 ./something.bash。
【讨论】:
使用 GNU find 您可以获得带有修改时间戳的目录列表,对该列表进行排序并输出最新的:
find . -mindepth 1 -maxdepth 1 -type d -printf "%T@\t%p\0" | sort -z -n | cut -z -f2- | tail -z -n1
或换行符分隔
find . -mindepth 1 -maxdepth 1 -type d -printf "%T@\t%p\n" | sort -n | cut -f2- | tail -n1
使用 POSIX 查找(没有-printf),如果有,您可以运行stat 以获取文件修改时间戳:
find . -mindepth 1 -maxdepth 1 -type d -exec stat -c '%Y %n' {} \; | sort -n | cut -d' ' -f2- | tail -n1
如果没有stat,则可以使用纯shell 解决方案,方法是将[[ bash 扩展替换为[,如this answer。
【讨论】: