2

Me being me, I went playing around with the terminal (zsh.) One of the things I tried (in an empty directory) was mkdir test; ls | cd This should make a folder then print all folders (so just that one) and pipe the output to cd. So I expected it to take me to the test directory but instead I got (pwd now: ~) and it took me back to the home directory. Does anyone know why this is? Looking it up gives nothing useful.

EDIT: It takes me to the ~ directory because cd doesn't accept stdin inputs, but rather the directory is an argument. What I still want to know is why running ls | cd gives the output (pwd now: ~) instead of just nothing. Running echo test | cd gives no output but ls | cd does.

joshmeranda
  • 3,001
  • 2
  • 10
  • 24
Base64__
  • 97
  • 8
  • Does this answer your question? [bash - how to pipe result from the which command to cd](https://stackoverflow.com/questions/3437514/bash-how-to-pipe-result-from-the-which-command-to-cd) – joshmeranda Aug 24 '20 at 20:04
  • No, I was looking for why it gives the (pwd now: ~) output specifically, not how to make it not give that output. – Base64__ Aug 24 '20 at 20:13

1 Answers1

3

When you "pipe" input from one process or job to another, you are also spawning another process. Both of these jobs are said to be "children" of main process which called them (usually the process running the terminal emulator).

# 2 process are run here
# first job: echo
# second job: ls
echo "/home/" | ls

Looking at the source for zsh, it looks like when the cwd of a job differs from the original cwd of the job after execution, it will notify the user with a message like (pwd now: foo). This helps to ensure that the user knows exactly where the are in the directory tree, which is especially useful when they may not have intended to do so. Below is taken from jobs.c where the cwd (referred to as pwd) where among other things, the cwd (referenced as pwd) are compared before printing the (pwd now: foo) message. If they are different the message is printed, if they are equal it is not.

if ((lng & 4) || (interact && job == thisjob &&
              jn->pwd && strcmp(jn->pwd, pwd))) {
    doneprint = 1;
    fprintf(fout, "(pwd %s: ", (lng & 4) ? "" : "now");
    fprintdir(((lng & 4) && jn->pwd) ? jn->pwd : pwd, fout);
    fprintf(fout, ")\n");
    fflush(fout);
    }

When you pipe something into ch you are changing the cwd in a child process and some of the normal checks which hide this message when calling cd directly are bipassed. Otherwise cd words in the same way.

# changes directories into ./test
echo "test" | cd
# (pwd now: /path/to/test)

# changes directory to home
echo | cd
# (pwd now: /home/<username>)

# calling this again will not echo the message, since the cwd is already
# the home directory and no change occurs 
echo | cd

As for why the cwd is changed to the home directory (~) it is due to how cd behaves when no paths are given as an argument. Unlike a lot of linux commands, cd does not read from stdin for paths to move into. Due to this, piping into cd will simply populate stdin for cd, but that content is ignored. Because of this piping into cd is the same as just calling cd on its own.

# these next lines produce the same behavior
echo path/to/dir/test | cd
cd

When cd does not receive a path to move to, it will move you to your home directory (referenced on linux systems as ~)

# each of these lines produce the same behavior
cd /home/<username>
cd ~
cd
joshmeranda
  • 3,001
  • 2
  • 10
  • 24
  • so why does cd give the `(pwd now: ~)` output when I pipe text from ls into it? It doesn't give that output when i do `echo test | cd` or just `cd` but it does when i do `ls | cd`. – Base64__ Aug 25 '20 at 21:25
  • That seems like shell specific behavior, I couldn't reproduce it on `fish`, `bash`, or `sh`. Which shell and what version are you using? – joshmeranda Aug 25 '20 at 21:53
  • I'm using zsh because bash told me to use it – Base64__ Aug 25 '20 at 23:39
  • 1
    Oh ok, it looks like output specific to zsh's implementation or handling of the process. Let me take a look into it, and I'll update my answer – joshmeranda Aug 25 '20 at 23:49
  • 1
    I added a "shallow" explanation of the the root cause for the message from what I can gather from the source. I welcome any input from those more involved in its development or knowledgeable of `zsh` inner workings. – joshmeranda Aug 26 '20 at 01:48
  • Great answer. I arrived here because I'd tried `ls -a | grep mydir | cd` (trying to `cd` into `/mydir`. Anyway, I just wanted to be sure I hadn't accidentally deleted anything. Seems like it's harmless – stevec Feb 09 '21 at 22:57