如何制作自己的“shell 命令”(例如 mkdir/cd 组合)?

Chr*_*oms 41 bash

我不知道有多少次我希望有一个既可以创建目录又可以移动到该目录的命令。基本上,我想要相当于以下内容:

mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path
Run Code Online (Sandbox Code Playgroud)

但只需要输入/arbitrarily/long/path一次,例如:

mk-cd /arbitrarily/long/path
Run Code Online (Sandbox Code Playgroud)

我尝试创建一个脚本来执行此操作,但它只会更改脚本中的目录。我希望 shell 中的目录也已更改。

#!/bin/bash
mkdir $1
cd $1
export PWD=$PWD
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

jll*_*gre 92

最简单的方法是使用shell函数:

mkcd() {
    mkdir -p -- "$1" && cd -- "$1"
}
Run Code Online (Sandbox Code Playgroud)

将它放在您的.bashrc文件中,使其像另一个 shell 命令一样可供您使用。

它不能作为外部脚本工作的原因是cd改变了正在运行的脚本的当前目录,但不影响调用的脚本。这是设计使然!每个进程都有自己的工作目录,由其子进程继承,但相反是不可能的。

除非是管道的一部分,在后台运行或明确地在子 shell 中运行,否则 shell 函数不会在单独的进程中运行,而是在同一个进程中运行,就像命令已被获取一样。然后可以通过函数更改当前目录外壳。

&&这里使用的使用的手段两个命令分开,如果第一命令成功(mkdir),运行第二个(cd)。因此,如果mkdir无法创建请求的目录,则尝试进入该目录是没有意义的。一个错误信息被打印出来mkdir,就是这样。

-p使用 with的选项mkdir告诉此实用程序创建作为参数传递的目录名称完整路径的一部分的任何缺失目录。一个副作用是,如果您要求创建一个已经存在的目录,该mkcd函数不会失败并且您最终会进入该目录。这可能被视为问题或功能。在前一种情况下,可以修改函数,例如简单地警告用户的方式:

mkcd() {
    if [ -d "$1" ]; then
        printf "mkcd: warning, \"%s\" already exists\n" "$1"
    else
        mkdir -p "$1" 
    fi && cd "$1"
}
Run Code Online (Sandbox Code Playgroud)

如果没有这个-p选项,初始函数的行为就会大不相同。

如果包含要创建的目录的目录尚不存在,mkdir则该功能也会失败。

如果要创建的目录已经存在,mkdir也会失败并且cd不会被调用。

最后,请注意设置/导出PWD是没有意义的,因为 shell 已经在内部完成了。

编辑:我--为该函数的两个命令添加了选项,以允许以破折号开头的目录名称。

  • 您还应该补充一点,除非将该命令添加到`~/.bashrc` 或其他初始化脚本之一,否则该命令不会永久可用。 (5认同)
  • @ThomasPadron-McCarthy 您应该开始将 tcsh 的别名更像是受限函数。 (3认同)

AFH*_*AFH 32

我想添加一个替代解决方案。

如果您使用 or命令调用它,您的脚本起作用:.source

. mk-cd /arbitrarily/long/path
Run Code Online (Sandbox Code Playgroud)

如果你这样做export,脚本中的就没有必要了。您可以绕过键入.通过使用alias

alias mk-cd='. mk-cd'
Run Code Online (Sandbox Code Playgroud)

这样做的原因是脚本通常在子 shell 中运行,因此它的环境在完成时丢失,但.(or source) 命令强制它在当前 shell 中运行。

这种技术对于对于函数来说太复杂或正在开发且经常编辑的命令序列非常有用:一旦alias输入到 中.bash_aliases,您就可以随意编辑脚本而无需重新初始化。

请注意以下事项:-

如果您编写的脚本必须使用./source命令调用,则有两种方法可以确保这一点:-

  1. 出于某种原因,使用./调用的脚本source不需要是可执行的,因此只需删除此权限,该脚本要么不会在“$PATH”中找到,要么如果使用显式路径调用将给出权限错误。

  2. 或者,可以在脚本的开头使用以下技巧:

bind |& read && { echo 'Must be run from "." or "source" command'; exit 1; }
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为在子 shell 中bind发出警告,但没有错误状态:因此read用于在没有输入时给出错误。

  • @cst1992 - 不,命令完全不同:`export var` 将内部变量 `var` 复制到环境中,在那里它被继承并作为任何子 shell 中的变量导入,但它对父 shell 没有影响. 通常会创建一个子 shell 来运行脚本,并且它所做的任何更改(包括导出的变量)在完成时都会丢失。为了让脚本在 shell 中设置变量,它必须在该 shell 中运行,这就是 `.` 命令所做的:在不创建子 shell 的情况下运行脚本。奇怪的是,由`.` 运行的脚本不需要具有可执行权限。 (2认同)

Ria*_*iaD 13

不是单个命令,但您不必重新键入刚刚使用的所有路径!$(这是 shell 历史记录中上一个命令的最后一个参数)。

例子:

mkdir -p /arbitrarily/long/path
cd !$
Run Code Online (Sandbox Code Playgroud)