1

I have made a cli which computes the location of a certain directory, and I would really like to have the script change into it. My first approach was ./myscript | cd which I've learned doesn't work as 1. cd doesn't take piped arguments, and 2. the script won't be allowed to change the directory of the parent shell.

I learned that there are workarounds, and I tried creating a function in .bash_profile:

function cdir(){
  DIR=""
  while read LINE; do
      DIR=$LINE
  done
  echo $DIR
  cd $DIR
}

Now running ./myscript | cdir the correct directory is output, however, the directory is still not changed.

Using command substitution works: cd $(./myscript), but I'd really prefer to be able to write this using pipe. Do you have any idea how I can get this to work, or at least explain why it isn't possible?

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Jørgen
  • 8,820
  • 9
  • 47
  • 67
  • 2
    If you run `pwd` at the end of your function, you'll see that the directory *was* changed within its scope. Whether that scope matches parent scope in a pipeline in unspecified by POSIX, and varies shell-to-shell (and between various runtime configurations for a specific shell -- it's possible to get the last pipeline element run in the parent in new versions of bash, but only if you disable job control support). – Charles Duffy Oct 01 '17 at 18:24

1 Answers1

3

cd changes the current working directory, which is an attribute of the process. When you use a pipeline, shell creates a subprocess and the effect of cd (inside your function) is lost when the subprocess finishes.

cd -- "$(./myscript)"

is the right way of doing it. Here, cd runs in your current shell.


See also:

codeforester
  • 39,467
  • 16
  • 112
  • 140