开发者

How to change current working directory inside command_not_found_handle

开发者 https://www.devze.com 2023-02-17 19:48 出处:网络
I\'m trying to write a not found handle in Bash that does the following: If $1 exists and it\'s a directory, cd into开发者_Go百科 it.

I'm trying to write a not found handle in Bash that does the following:

  1. If $1 exists and it's a directory, cd into开发者_Go百科 it.
  2. If $1 exists inside a user defined directory $DEV_DIR, `cd into it.
  3. If the previous conditions don't apply, fail.

Right now I have something like this:

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
}

And although it seems to be working (the echo pwd command prints the expected dir), the directory in the actual shell does not change.

I was under the impression that since this is a function inside my .bashrc the shell wouldn't fork and I could do the cd but apparently that's not working. Any tips on how to solve this would be appreciated.


I think what's going on is that the shell fork()s after setting up any redirections but before looking for commands, so command_not_found_handle can't affect the interactive shell process.


What you seem to want to do may partly possible using the autocd feature:

shopt -s autocd

From man bash:

autocd - If set, a command name that is the name of a directory is executed as if it were the argument to the cd com‐ mand. This option is only used by interactive shells.

Otherwise, just create a function that you invoke by name that performs the actions you are trying to use command_not_found_handle for.


It won't change directies if you run this program as a script in your main shell because it creates a sub-shell when it executes. If you source the script in your current shell then it will have the desired effect.

~/wbailey> source command_not_found.sh

That said, I think the following would achieve the same result:

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

just replace the ".." with your env var defined directory and create an alias in your .bashrc file.


I've had the very same wish and the solution that I've been using for a while was opening a new tab in gnome terminal by issuing the command gnome-terminal --tab --working-directory="$FOLDER" from inside the command_not_found handle.

But today I've come up with a solution which is not tied to a specific terminal application, but has exactly the intended behaviour.

The solution uses the PROMPT_COMMAND, which is run before each prompt. The PROMPT_COMMAND is bound to a function responsible for checking for a file related to current shell, and cd'ing into the directory specified in that file.

Then, the command_not_found_handle fills in the file when a change in directory is desired. My original command_not_found_handle also checkout a git branch if the current directory is a git repository and the name matches an existing branch. But to keep focus on answering the current question, I've stripped that part of code.

The command_not_found_handle uses find for searching for the directory matching the given name and goes only 2 levels deep in the directory tree, starting from a configured list.

The code to be added to bash_rc follows:

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
}
0

精彩评论

暂无评论...
验证码 换一张
取 消