Background#
Last night, I wanted to use fzf in conjunction with cd, which means passing the result of fzf to cd to execute, so I came up with this command:
cd $(fd --type d | fzf)
This command can indeed accomplish the task, but there are two problems:
- If you exit directly, you will return to the home directory because the execution result of
$(..)
is empty. - It is cumbersome to enter so much every time.
Using alias#
Then I tried using an alias, so I added the following to .zshrc
:
alias cdf="cd $(fd --type d | fzf)"
The result is that it cannot be executed directly because it directly recognizes the $(..)
part and executes it, but the rest will not be executed.
Using a shell script#
Then I wrote this file:
#!/bin/sh
path=$(fd --type d --strip-cwd-prefix --hidden --follow --exclude .git --exclude node_modules | fzf)
if [ -z "$path" ]; then
exit
fi
cd "$path" || exit
The result is also not working. I added a line echo "$PWD"
at the bottom, and I saw that it was executed, but it became ineffective after the program exited.
Solution#
Finally, I found that I can use source xxx
or . xxx
to solve it. In the end, I used alias+shell script to complete this operation:
alias cdf="source /path/to/cdf"
At the same time, it also solves the two problems mentioned above.
Why can source solve it?#
The reason why running the shell script directly doesn't work is because it is not running in the current shell environment, but in a subshell, so the result cannot change the current file directory.
However, source
or .
represents executing in the current shell environment, so it can succeed.
Update#
2022/11/18#
Today I discovered an easier solution, which is to write a shell function:
function cd() {
cd "$(fzf)"
}
Add it to .zshrc
(I'm using zsh), and then enter cd
in the command line.