我已经数不清有多少次希望有一个命令既能创建目录又能移动到该目录。基本上,我希望得到以下等价的命令:
mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path
但只需输入/arbitrarily/long/path
一次,例如:
mk-cd /arbitrarily/long/path
我尝试创建一个脚本来执行此操作,但它只会更改脚本内的目录。我希望 shell 中的目录也发生更改。
#!/bin/bash
mkdir $1
cd $1
export PWD=$PWD
我怎样才能让它发挥作用?
答案1
最简单的方法是使用 shell 函数:
mkcd() {
mkdir -p -- "$1" && cd -- "$1"
}
将其放置在您的.bashrc
文件中,使其像其他 shell 命令一样可供您使用。
它不能作为外部脚本工作的原因是它cd
改变了正在运行的脚本的当前目录,但不影响调用脚本的目录。这是设计使然!每个进程都有自己的工作目录,并由其子进程继承,但相反的情况则不可能。
除非是管道的一部分、在后台运行或明确在子 shell 中运行,否则 shell 函数不会在单独的进程中运行,而是在同一个进程中运行,就像命令已被调用一样。然后可以通过函数更改当前目录 shell。
这里使用&&
来分隔两个命令,意思是如果第一个命令成功 ( mkdir
),则运行第二个命令 ( cd
)。因此,如果mkdir
无法创建请求的目录,则尝试进入该目录是没有意义的。将打印一条错误消息,mkdir
仅此而已。
-p
使用的选项是mkdir
告诉此实用程序创建任何缺失的目录,该目录是作为参数传递的目录名的完整路径的一部分。一个副作用是,如果您要求创建一个已经存在的目录,该mkcd
函数不会失败,您将最终进入该目录。这可能被视为一个问题或一个功能。在前一种情况下,可以修改该函数,例如,只需向用户发出警告:
mkcd() {
if [ -d "$1" ]; then
printf "mkcd: warning, \"%s\" already exists\n" "$1"
else
mkdir -p "$1"
fi && cd "$1"
}
如果没有这个-p
选项,初始函数的行为将会非常不同。
如果包含要创建的目录的目录尚不存在,mkdir
则该函数也会失败。
如果要创建的目录已经存在,mkdir
也会失败并且cd
不会被调用。
最后,请注意设置/导出PWD
是没有意义的,因为 shell 已经在内部执行了此操作。
编辑:我--
向两个命令都添加了选项,以使目录名能够以破折号开头。
答案2
我想添加一个替代解决方案。
你的脚本将要如果使用.
或source
命令调用它,则可以工作:
. mk-cd /arbitrarily/long/path
如果这样做,export
脚本中的 就没有必要了。您可以.
使用 来绕过输入alias
:
alias mk-cd='. mk-cd'
这种方法之所以有效,是因为脚本通常在子 shell 中运行,因此其环境在完成时会丢失,但.
(或source
)命令强制它在当前 shell 中运行。
这种技术对于那些对于功能来说过于复杂或正在开发且经常编辑的命令序列很有用:一旦输入alias
,.bash_aliases
您就可以随意编辑脚本而无需重新初始化。
请注意以下几点:-
如果你编写了一个脚本必须.
可以通过/命令调用source
,有两种方法可以确保这一点:-
.
由于某种原因,使用/调用的脚本source
不需要是可执行的,因此只需删除此权限,该脚本将不会在“$PATH”中找到,或者在使用明确路径调用时会出现权限错误。或者,可以在脚本的开头使用以下技巧:
bind |& read && { echo 'Must be run from "." or "source" command'; exit 1; }
这是因为在子 shell 中bind
发出了警告,尽管没有错误状态:因此read
用于在没有输入时给出错误。
答案3
不是单个命令,但您不必重新输入只需使用的所有路径!$
(这是 shell 历史记录中上一个命令的最后一个参数)。
例子:
mkdir -p /arbitrarily/long/path
cd !$