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"
它的作用与具有空值的参数相同,即它扩展为空字符串。这与无参数不同,例如ls
与ls ""
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
不起作用,所以我不会对此发表评论。