如何更改command_not_found_handle中的当前工作目录

时间:2011-03-20 17:45:09

标签: bash shell sh bash4

我正在尝试在Bash中编写一个未找到的句柄来执行以下操作:

  1. 如果存在$ 1且它是一个目录cd
  2. 如果$ 1存在于用户定义的目录$DEV_DIR中,`cd into it。
  3. 如果以前的条件不适用,则失败。
  4. 现在我有这样的事情:

    export DEV_DIR=/Users/federico/programacion/
    
    function command_not_found_handle () {
        if [ -d $1 ]; then          # the dir exists in '.'
            cd $1
        else
            to=$DEV_DIR$1
            if [ -d $to ]; then
                cd $to
                echo `pwd`
            else
                echo "${1}: command not found"
            fi
        fi
    }
    

    虽然它似乎正在工作(echo pwd命令打印预期的目录),但实际shell中的目录不会改变。

    我的印象是,由于这是我的.bashrc内部的一个函数,shell不会分叉,我可以执行cd,但显然这不起作用。任何有关如何解决这个问题的提示都将受到赞赏。

4 个答案:

答案 0 :(得分:3)

认为在设置任何重定向之后但在查找命令之前,shell fork()发生了什么,因此command_not_found_handle不会影响交互式shell进程

答案 1 :(得分:1)

使用autocd功能部分可能会使您想要做的事情:

shopt -s autocd

来自man bash

  

autocd - 如果设置,则为命令名,即目录名                         执行就好像它是cd com-的参数一样                         普通话。此选项仅供交互式shell使用。

否则,只需创建一个按名称调用的函数,该函数执行您尝试使用command_not_found_handle的操作。

答案 2 :(得分:0)

如果您将此程序作为主shell中的脚本运行,则不会更改直接,因为它在执行时会创建子shell。如果您在当前shell中获取脚本,那么它将具有所需的效果。

~/wbailey> source command_not_found.sh

那就是说,我认为以下结果会达到同样的结果:

wesbailey@feynman:~/code_katas> cd xxx 2> /dev/null || cd ..; pwd
/Users/wesbailey

只需将“..”替换为您的env var定义的目录,并在.bashrc文件中创建一个别名。

答案 3 :(得分:0)

我有同样的愿望,一段时间以来一直在使用的解决方案是通过从gnome-terminal --tab --working-directory="$FOLDER"句柄内部发出命令command_not_found在gnome终端中打开一个新标签页。

但是今天我想出了一个解决方案,该解决方案与特定的终端应用程序无关,但是具有预期的行为。

该解决方案使用PROMPT_COMMAND,它在每个提示之前运行。 PROMPT_COMMAND绑定到一个函数,该函数负责检查与当前shell相关的文件,并将其CD到该文件中指定的目录中。

然后,当需要更改目录时,command_not_found_handle将填写文件。如果当前目录是git存储库,并且名称与现有分支匹配,我原来的command_not_found_handle也会签出git分支。但是,为了专注于回答当前问题,我删除了那部分代码。

command_not_found_handle使用find搜索与给定名称匹配的目录,并且从配置的列表开始,目录树仅深入两层。

要添加到bash_rc的代码如下:

PROMPT_COMMAND=current_shell_cd
CD_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/bash-cd/$$.cd"

current_shell_cd() {
    if [ -r "$CD_FILE" ]; then
        local CD_TARGET="$( cat "$CD_FILE" )"
        [ ! -z "$CD_TARGET" ] && cd "$CD_TARGET" 2>/dev/null
        rm "$CD_FILE"
    fi
}

command_not_found_handle () { 
    local COMMAND="$1";
    # List folders which are going to be checked
    local BASE_FOLDER_LIST=(
        "$HOME/Desenvolvimento"
        "/var/www/html"  
        "$HOME/.local/opt/"
    )
    local FOLDER=$(
        find "${BASE_FOLDER_LIST[@]}" \
             -maxdepth 2 -type d \
             -iname "$COMMAND" -print -quit )
    if [ ! -z "$FOLDER" -a -d "$FOLDER" ]
    then
        mkdir -p "$( dirname "$CD_FILE" )"
        echo "$FOLDER" > "$CD_FILE"
    else
        printf "%s: command not found\n" "$1" 1>&2
        return 127
    fi
}