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
  • 257,635
  • 38
  • 339
  • 400
Jørgen
  • 8,532
  • 9
  • 46
  • 66
  • 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
  • 34,080
  • 14
  • 96
  • 122