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. - If $1 exists inside a user defined directory
$DEV_DIR
, `cd into it. - 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
}
精彩评论