简体   繁体   English

获取 Bash 中变量的最新目录

[英]Get the newest directory to a variable in Bash

I would like to find the newest sub directory in a directory and save the result to variable in bash.我想在目录中找到最新的子目录并将结果保存到bash中的变量中。

Something like this:像这样的东西:

ls -t /backups | head -1 > $BACKUPDIR

Can anyone help?任何人都可以帮忙吗?

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

$(...)在子shell 中评估语句并返回输出。

There is a simple solution to this using only ls :仅使用ls有一个简单的解决方案:

BACKUPDIR=$(ls -td /backups/*/ | head -1)
  • -t orders by time (latest first) -t按时间-t (最新在前)
  • -d only lists items from this folder -d仅列出此文件夹中的项目
  • */ only lists directories */只列出目录
  • head -1 returns the first item head -1返回第一项

I didn't know about */ until I found Listing only directories using ls in bash: An examination .我不知道*/直到我发现在 bash 中仅使用 ls 列出目录:一项检查

This ia a pure Bash solution:这是一个纯 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"

It skips symlinks, including symlinks to directories, which may or may not be the right thing to do.它跳过符号链接,包括指向目录的符号链接,这可能是也可能不是正确的做法。 It skips other non-directories.它跳过其他非目录。 It handles directories whose names contain any characters, including newlines and leading dots.它处理名称包含任何字符的目录,包括换行符和前导点。

Well, I think this solution is the most efficient:嗯,我认为这个解决方案是最有效的:

path="/my/dir/structure/*"
backupdir=$(find $path -type d -prune | tail -n 1)

Explanation why this is a little better:解释为什么这更好一点:

We do not need sub-shells (aside from the one for getting the result into the bash variable).我们不需要子外壳(除了用于将结果放入 bash 变量的那个)。 We do not need a useless -exec ls -d at the end of the find command, it already prints the directory listing.我们不需要在find命令末尾使用无用的-exec ls -d ,它已经打印了目录列表。 We can easily alter this, eg to exclude certain patterns.我们可以很容易地改变这一点,例如排除某些模式。 For example, if you want the second newest directory, because backup files are first written to a tmp dir in the same path:例如,如果您想要第二个最新的目录,因为备份文件首先写入同一路径中的 tmp 目录:

backupdir=$(find $path -type -d -prune -not -name "*temp_dir" | tail -n 1)

With GNU find you can get list of directories with modification timestamps, sort that list and output the newest:使用 GNU find,您可以获得带有修改时间戳的目录列表,对该列表进行排序并输出最新的:

find . -mindepth 1 -maxdepth 1 -type d -printf "%T@\t%p\0" | sort -z -n | cut -z -f2- | tail -z -n1

or newline separated或换行符分隔

find . -mindepth 1 -maxdepth 1 -type d -printf "%T@\t%p\n" | sort -n | cut -f2- | tail -n1

With POSIX find (that does not have -printf ) you may, if you have it, run stat to get file modification timestamp:使用 POSIX find (没有-printf ),您可以(如果有)运行stat以获取文件修改时间戳:

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

Without stat a pure shell solution may be used by replacing [[ bash extension with [ as in this answer .而不stat纯壳溶液可以通过更换使用[[使用bash扩展[如在此答案

The above solution doesn't take into account things like files being written and removed from the directory resulting in the upper directory being returned instead of the newest subdirectory.上面的解决方案没有考虑到文件被写入和从目录中删除导致返回上层目录而不是最新的子目录之类的事情。

The other issue is that this solution assumes that the directory only contains other directories and not files being written.另一个问题是此解决方案假定目录仅包含其他目录而不包含正在写入的文件。

Let's say I create a file called "test.txt" and then run this command again:假设我创建了一个名为“test.txt”的文件,然后再次运行此命令:

echo "test" > test.txt
ls -t /backups | head -1
test.txt

The result is test.txt showing up instead of the last modified directory.结果是显示 test.txt 而不是最后修改的目录。

The proposed solution "works" but only in the best case scenario.建议的解决方案“有效”,但仅适用于最佳情况。

Assuming you have a maximum of 1 directory depth, a better solution is to use:假设您最多有 1 个目录深度,更好的解决方案是使用:

find /backups/* -type d -prune -exec ls -d {} \; |tail -1

Just swap the "/backups/" portion for your actual path.只需将“/backups/”部分交换为您的实际路径。

If you want to avoid showing an absolute path in a bash script, you could always use something like this:如果你想避免在 bash 脚本中显示绝对路径,你总是可以使用这样的东西:

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

I would like to find the newest sub directory in a directory and save the result to variable in bash.我想在目录中找到最新的子目录,并将结果保存到bash中的变量中。

Something like this:像这样的东西:

ls -t /backups | head -1 > $BACKUPDIR

Can anyone help?有人可以帮忙吗?

Your "something like this" was almost a hit:你的“这样的东西”几乎很受欢迎:

BACKUPDIR=$(ls -t ./backups | head -1)

Combining what you wrote with what I have learned solved my problem too.结合你写的内容和我学到的东西也解决了我的问题。 Thank you for rising this question.谢谢你提出这个问题。

Note: I run the line above from GitBash within Windows environment in file called ./something.bash .注意:我在名为./something.bash文件中的 Windows 环境中从 GitBash 运行上面的行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM