0

I have a function, which I would hope would get me a fuzzy search on the latest directories I have been looking at and save me time, a simple 1 liner:

dirs | sed 'y/ /\n/' | fzf | xargs cd

2 hours later I can't figure out what's wrong ) :

I keep getting errors like:

/usr/bin/cd: line 4: cd: ~/Downloads/demo: No such file or directory

Even when the directory does exist, no matter what I do. What is up with cd, why doesn't this work?

Thanks for Comment: More Info I've tried a few other ways, such as writing a function:

fdr() {
     local dir
     dir=`dirs | sed 'y/ /\n/' | fzf`
     cd $dir
}  

Even though dir has the correct value, I get the same error as seen above.

My Final Function

Thanks for the help, sub shells were doing my head in, here is my final answer, bit hackey, but what isn't these days.

fdr() {
  local dir
  myusernmae=`whoami`
  dir=`dirs | sed 'y/ /\n/' | sed "s/~/\/Users\/$myusernmae/g" | fzf +m`
  cd "$dir"
}

1 Answers1

6

There are three issues here:

  1. The directory pathname is given to cd as the literal string ~/Downloads/demo even though the correct path may be something like /Users/snickers/Download/demo.

    Usually when you type cd ~/Downloads/demo on the command line, the shell will expand the tilde to the path of your home directory before running the cd command. This does not happen here because tilde expansion happens before variable expansion (see "How to understand the order between expansions?").

    Assuming that you're using the bash shell, using dirs -l may bypass this issue by letting dirs output the full path.

  2. cd is a shell built-in command. On your macOS machine, it is also available as the external command /usr/bin/cd, which is why you're not getting a "command not found" error like many other Unix user would get when using cd with xargs. However, an external cd command can never change the directory for the current shell. This is described in "Why is cd not a program?" and "where is `cd` located?" and in similar questions. Your shell function variation bypasses this issue since its using your shell's built-in cd command.

  3. The last issue, which is a variant of the 2nd issue and which really doesn't come into play because of the other issues, is that the cd command, when executed by xargs, is not only an external command that can't change the working directory for the calling shell, but the command that is calling it is xargs, which in turn is running in a sub-shell as a stage of your pipeline. Changing the shell in a sub-shell won't change it in the parent shell.

You should be able to use

fdr () {
   cd "$( dirs -l -p | fzf )"
}

where dirs -l -p outputs one directory from the directory stack in bash per line, with tildes expanded. This assumes that you don't have directories on the stack with embedded newlines in their names, but will support directories with spaces (which your own function does not do, partly because of the sed transformations and partly because of not quoting the expansion of $dir).

Kusalananda
  • 333,661