0

I was running the Linux Shell commands in a particular way, I wanted to figure out if both ways of running them would generate the same result.

Example 1:

echo "echo "hi"" | /bin/sh

hi

Example 2:

echo "pwd" | /bin/sh

/root/test

Example 3:

Here, assume that there's a file called test.txt which only contains the word "test"

echo "cat test.txt" | /bin/sh

test

So far, everything seemed to working fine, but then when I typed the following

echo "cd .." | /bin/sh

Nothing happened, which shouldn't be the case, because if I type cd .. without | /bin/sh and press Enter, the Shell takes me back to the previous path which in this case would be /root

So, I just want to know what's the actual list of available commands for use via /bin/sh

Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
NoahVerner
  • 937
  • 2
  • 9
  • 24
  • 6
    Your `cd ..` __does__ work, it changes the working directory in the subprocess. This has no effect on the parent process though. – tkausl Nov 24 '21 at 10:25
  • why? :( @tkausl – NoahVerner Nov 24 '21 at 10:27
  • 4
    Security, basically. Any started process is only allowed to affect its own environment. Or whatever script you run could wreck whatever process it was started from. – DevSolar Nov 24 '21 at 10:28
  • 3
    "System calls" generally refers to the OS ABI. These are simply "commands". – tripleee Nov 24 '21 at 10:58
  • 1
    @NoahVerner : By design, each process has its own environment and can change the environment. It can also pass a (possibly modified) environment to a child process. It can't modify the environment of the parent process. The environment implicitly contains the working directory, and therefore, your example does not work as you expect. – user1934428 Nov 24 '21 at 12:29
  • 1
    If you do a `sh -c 'cd ..; pwd'`, you can see that the `cd` had the desired effect. – user1934428 Nov 24 '21 at 12:32

2 Answers2

1

After running echo "cd .." | /bin/sh you get back to the previous folder because the above command runs a new shell instance, and it changes the current path inside the new subshell, and not into the caller instance.

For the same reason we never create helper script to change dir, but we use the aliases which run in the context of the calling shell.

Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
1

You can run any command in this way, but they are executed by the inner shell, and so only have an effect within that shell.

Printing text to the screen using cat, echo or pwd is permanent, even after the inner shell has exited, because actually the inner shell writes to its standard output, and the outer shell (which you are using to type the commands) has linked the inner shell's output to its own output, which goes to the screen.

The idea of a "current working directory" is not system-wide, but it attached to a process like a shell. The cd command changes the current shell's working directory, but it does not effect the outer shell's working directory. Additionally, any new process started by a shell will start with the parent shell's working directory, but changing directory afterwards in either process will not have an effect on the other.

Environment variables are another thing that only have an effect on the current shell, and you get to choose whether environment variables are passed on to sub-processes by exporting them, or not.

For example, the following will give you the "correct" parent directory:

echo "cd ..; pwd" | /bin/sh
Jelaby
  • 1,107
  • 1
  • 9
  • 19
  • Wow, that's deep and complex tbh, but thanks! My question was answered :) – NoahVerner Nov 24 '21 at 10:47
  • 1
    It might be deep, but I wouldn't say it's complex. The rule is that processes can't affect other processes unless something specifically has been done to allow it, by reading or writing from some shared resource like the filesystem, the screen, a pipe, shared memory or whatever. – Jelaby Nov 24 '21 at 11:02
  • 1
    Oh, I've just realised that this doesn't explain how `cd` itself can change the directory of shell in which you ran it: it is a "shell builtin command" which is a command understood by the shell itself without invoking an external process. – Jelaby Nov 24 '21 at 11:07