获取Bash中变量的最新目录

获取Bash中变量的最新目录,bash,Bash,我想在一个目录中找到最新的子目录,并将结果保存到bash中的变量中 大概是这样的: ls -t /backups | head -1 > $BACKUPDIR LOCALPATH=/backups DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1) 有人能帮忙吗 BACKUPDIR=$(ls -td /backups/*/ | head -1) $(…)对子shell中的语句求值并返

我想在一个目录中找到最新的子目录,并将结果保存到bash中的变量中

大概是这样的:

ls -t /backups | head -1 > $BACKUPDIR
LOCALPATH=/backups
DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1)
有人能帮忙吗

BACKUPDIR=$(ls -td /backups/*/ | head -1)

$(…)
对子shell中的语句求值并返回输出。

上述解决方案不考虑从目录中写入和删除文件等情况,导致返回的是上层目录而不是最新的子目录

另一个问题是,此解决方案假定该目录仅包含其他目录,而不包含正在写入的文件

假设我创建了一个名为“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脚本中显示绝对路径,可以始终使用以下内容:

ls -t /backups | head -1 > $BACKUPDIR
LOCALPATH=/backups
DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1)

要使用
ls-t
获取最新文件夹,如果目录中不只有目录,则可能需要区分文件和文件夹。使用一个简单的循环,您将获得安全、快速的结果,并允许在将来轻松实现不同的过滤器:

while read i ; do if [ -d "${i}" ] ; then newestFolder="${i}" ; break ; fi ; done < <(ls -t)

你不会用它的。我把它放在那里只是为了你的可见性,因为在这种情况下它不会影响结果。

好吧,我认为这个解决方案是最有效的:

path="/my/dir/structure/*"
backupdir=$(find $path -type d -prune | tail -n 1)
解释为什么这会好一点:

我们不需要子shell(除了用于将结果输入bash变量的子shell)。 我们不需要一个无用的
-exec ls-d
find
命令的末尾,它已经打印了目录列表。 我们可以很容易地改变这一点,例如排除某些模式。例如,如果您想要第二个最新目录,因为备份文件首先写入同一路径中的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
    返回第一项
直到我找到了,我才知道
*/

你的“类似这样的东西”几乎是一部畅销书:

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 find(没有
-printf
),如果有,可以运行
stat
,以获取文件修改时间戳:

find . -mindepth 1 -maxdepth 1 -type d -exec stat -c '%Y %n' {} \; | sort -n | cut -d' ' -f2- | tail -n1

如果没有
stat
,则可以使用纯shell解决方案,将
[[
bash扩展替换为
[
如中所示。

尽管该解决方案已被接受,且投票率较高,但仍存在一些问题。如果目录中的最新项不是目录,则该解决方案不起作用。如果最新子目录的名称以“.”开头,则该解决方案不起作用。如果最新子目录的名称包含换行符,则该解决方案不起作用。投诉关于
ls
的使用。有关处理
ls
输出的危险性的详细说明,请参阅。尽管有升级投票,但此解决方案不起作用。
find/backups/*-type d-prune-exec…
按shell展开
/backups/*
时生成的顺序处理目录。顺序是确定的由名称而不是时间戳来终止。列出的最后一个目录通常不是最新的目录。在回答pjh对接受答案的评论时,“如果最新目录以“.”开头,则不起作用”,这也与我的答案有关。如果要包括以开头的文件夹。(但排除./and../)您可以将ls更改为:ls-td/backups/{.[^.],}?*/这主要是我自己的参考。使用--quoting style=shell escape似乎解决了我提出的ls的许多问题,这不是对文件夹进行排序。这是因为它遇到的问题与上的注释中描述的问题相同。这是唯一不会对有效文件任意中断的解决方案。