函数中的“cd”有效,除非它不起作用

函数中的“cd”有效,除非它不起作用

cd 到目录后我做的第一件事是使用“ls”,我想很多人都是这样。所以我决定在 .bashrc 中定义一个函数来同时完成这两个任务。这就是我想出的:

cs() {
    if [[ ! "$1" ]] && [[ ! "$HOME" ]]
    then
        echo "I am completely lost and can't go home!"
        exit 1
    fi
    cd "$1" && ls --group-directories-first -h --color=auto
}

这在所有情况下都有效,但只有一种情况除外:当我没有传递任何参数时。无论是否设置 $HOME,它都不会执行任何操作并退出。我最终分解了第一行并得到了这个:

cs() {
    if [[ ! "$1" ]]
    then
        if [[ ! "$HOME" ]]
        then
            echo "I am completely lost and can't go home!"
            exit 1
        else
            cd && ls --group-directories-first -h --color=auto
        fi
    else
        cd "$1" && ls --group-directories-first -h --color=auto
    fi
}

这段代码完全按照我的预期工作。在这两者之间,我有一个具有非常奇怪行为的版本(不幸的是我保存了它,但这两个版本的差异非常小),其中如果我用参数引发“cs”,它会给我输出该目录的“ls”...但不会更改目录!由于代码仅将参数传递给“cd”,并且 ls 会退回到在当前目录上工作的默认行为(在这个丢失的版本中也是这种情况),而且我从来没有放过第二个“cd” ”在同一代码块中的“ls”之后,据我所知,这甚至不应该是可能的。

我只是想了解这里发生了什么事。我刚刚开始学习脚本编写,我认为这将是一项非常简单的任务,但似乎已经变成了一个很好的学习机会。为什么这些在我看来几乎相同的函数表现不同?

答案1

您只需使用cd为函数提供的原始参数列表来运行,然后运行您的ls命令。

cs () {
    cd "$@" && ls --group-directories-first --human-readable --color=auto
}

如果未使用任何参数调用该函数,则扩展"$@"将不会(根本),导致cd更改为当前用户的主目录或以任何适当的方式失败。否则,扩展将是带引号的参数列表(请注意,cd通常可以采用多个参数)。

该命令的内在逻辑cd已经处理了不接收参数且未设置的情况HOME,因此您的函数不必参与其中。

一般来说,您可能希望避免exit在函数中使用,因为这会退出当前 shell。相反,如果您希望从函数返回非零退出状态,请使用例如return 1

至于您关于cd未成功更改目录的评论:如果您在子 shell 中运行函数(或只是cd),则可能会发生这种情况,如(cd /)cat somefile | while ...; do cd ...; done(管道的每个部分在子 shell 中运行)。调用cd成功,当前目录已更改,但更改是对子 shell 的本地环境进行的,并且在父 shell 中不可见。子 shell 无法更改其父 shell 的环境。

答案2

cs() {
    ...
    cd "$1" && ls --group-directories-first -h --color=auto
}

这在所有情况下都有效,但只有一种情况除外:当我没有传递任何参数时。

当您没有任何参数时,$1未设置(如$2, $3, ...)。但是,当您在引号中扩展未设置的参数时,"$1"它的作用与具有空值的参数相同,即它扩展为空字符串。这与无参数不同,例如lsls ""or 进行比较unset foo; ls "$foo"

在 的情况下cd,Bash 中的行为是cd不带参数的调用转到$HOME,而cd使用空字符串作为参数调用则静默转到当前目录。

(这取决于 shell,如果您使用-P。如果参数是空字符串,则底层chdir()函数调用应该会给出错误,并且看起来 Bash 使用 公开该错误cd -P。其他一些 shell 仅chdir()针对.或当前目录,而 ksh给cd ""和提供“错误目录”错误cd -P ""。)

要将函数的所有参数传递给cd,请使用cd "$@"。与其他双引号扩展(生成一个字符串)不同,"$@"它是神奇的,它会完整地生成位置参数,作为不同的字符串,无论有多少(或不同的 shell“单词”,导致命令的不同参数)。因此,在没有参数的情况下,cd "$1"与 相同cd "",而cd "$@"与 just 相同cd

无论是否设置 $HOME,它都不会执行任何操作并退出。

我不明白为什么测试$HOME不起作用,所以我不会对此发表评论。

相关内容