繁体   English   中英

别名命令更改为最新目录

[英]alias command to change to newest directory

我想在我的bashrc文件中添加一个别名,以更改为当前目录中的最新子目录:

alias cdl="cd $(ls -t | head -n 1)"

问题是,当我获取文件时,该命令仅被评估一次。 如果我在更改目录后使用新的cdl命令,它仍然会尝试更改为旧目录,这可能不在我的新位置,并且对我来说并不是那么有用。

如何在每次运行时对此命令进行别名评估?

这是一种安全的方式来执行你想要的东西:安全我的意思是它会找到最新的目录 (而不仅仅是你的情况下的文件,虽然这可以修复)如果目录名包含空格,它将起作用, glob字符和换行符(可以通过添加适当的双引号来修复你的空格和glob字符,但不能用于换行符 - 有些人会认为处理换行符是不必要的;但是因为它可能,为什么不能有一个健壮的命令?) 。

我们将使用函数而不是别名!

cdl() {
    local mrd
    IFS= read -r -d '' mrd < <(
        shopt -s nullglob
        mrd=
        for i in */; do
            if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then
                mrd=$i
            fi
        done
        [[ $mrd ]] && printf '%s\0' "$mrd"
    ) && cd -- "$mrd"
}

演练

让我们首先关注内部部分:

shopt -s nullglob
mrd=
for i in */; do
    if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then
        mrd=$i
    fi
done
[[ $mrd ]] && printf '%s\0' "$mrd"

如果没有匹配项,则nullglob shell选项将使globs扩展为空。 for i in */的循环中使用了一个glob,带有一个斜杠,所以这会扩展到当前目录中的所有目录(如果没有目录,则没有任何内容,这要归功于nullglob )。

我们将mrd变量初始化为空字符串,然后循环遍历所有目录,循环变量i :如果mrd为空或者i扩展到比( -ntmrd更新的目录,那么我们用i替换mrd

在循环之后,如果mrd仍然为空(如果没有找到任何目录就会发生这种情况)我们什么都不做; 否则我们使用尾随的nullbyte打印该目录名称。

现在,外部:

IFS= read -r -d '' mrd < <( ... )

这将获取上面讨论的内部部分的输出(因此,无论是什么或最近目录的内容,具有尾随的nullbyte)并将其存储在变量mrd 如果没有读取任何内容,则read失败,否则read成功。 如果成功,我们很高兴在最新的目录中cd


我想提两点:

  • 可以将cdl写成:

     cdl() { local mrd i for i in */; do if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then mrd=$i fi done [[ $mrd ]] && cd -- "$mrd" } 

    如您所见,这不会设置nullglob ,这是必需的。 但是你不想全局设置它。 所以你需要保存旧的nullglob

     local old_nullglob=$(shopt -p nullglob) 

    并在功能结束时重置它:

     eval "$old_nullglob" 

    虽然这很好,但我现在试图避免这种情况,因为如果你的函数在完成之前退出(例如,如果用户中断它的执行),则nullglob将不会被重置。 这就是我选择在子shell中运行循环的原因!

  • 此时,您可能会认为以下内容可以解决问题:

     local mrd=$( ... loop that outputs most recent dir... ) && cd -- "$mrd" 

    不幸的是, $(...)修剪了尾随的换行符。 所以它不是100%工作,因此它被打破了。

事实证明,对我来说最健康的方法就是使用

IFS= read -r -d '' v < <( .... printf '...\0' )

如果你想要一个疯狂的功能:你可能发现我给的cdl没有处理隐藏目录。 那么我们如何允许如下调用:

cdl .

那也将开启搜索隐藏目录? 等等,我们如何允许函数参数,以便调用就好

cdl . /path/to/dir1 /path/to/dir2 ...

cd到最新的/path/to/dir1/path/to/dir2等子目录(包括隐藏的dirs)? 隐藏目录的开关应该是第一个参数,所以

cdl /path/to/dir1 .

cd进入/path/to/dir1和当前目录的最新非隐藏子目录,但是

cdl . /path/to/dir1 .

还包括隐藏目录。

cdl() {
    local mrd
    IFS= read -r -d '' mrd < <(
        [[ $1 = . ]] && shopt -s dotglob && shift
        (($#)) || set .
        shopt -s nullglob
        mrd=
        for d in "$@"; do
            if [[ ! -d $d ]]; then
                printf >&2 '%s is not a directory. Skipping.\n' "$d"
                continue
            fi
            [[ $d = / ]] && d=
            for i in "$d"/*/; do
                if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then
                    mrd=$i
                fi
            done
         done
        [[ $mrd ]] && printf '%s\0' "$mrd"
    ) && cd -- "$mrd"
}

我的下一个编辑将包括一个更新,允许调用cdl ,同时在计算π的最后一位数时也会冲泡咖啡。

如果你切换到单引号它应该工作:

alias cdl='cd -- "$(ls -t | head -n 1)"'

请注意,命令中的ls不一定提供最新的目录 ,它也可能产生一个文件,在这种情况下命令将无法按预期工作。 在这方面,添加--group-directories-first选项可能会有所帮助。

暂无
暂无

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

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