To understand this behavior, you need to understand how bash executes the commands passed to it on the command line. The key point is that if the command is simple enough, there is no fork (or clone or something like that).
$ strace -f -e clone,execve /bin/bash -c 'cat /proc/$$/cmdline' execve("/bin/bash", ["/bin/bash", "-c", "cat /proc/$$/cmdline"], []) = 0 execve("/bin/cat", ["cat", "/proc/2942/cmdline"], []) = 0 cat/proc/2942/cmdline+++ exited with 0 +++ $
OTOH, if the command is more complicated, bash forks:
$ strace -f -e clone,execve /bin/bash -c 'echo $$; cat /proc/$$/cmdline' execve("/bin/bash", ["/bin/bash", "-c", "echo $$; cat /proc/$$/cmdline"], [/* 80 vars */]) = 0 2933 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff64e6779d0) = 2934 Process 2934 attached [pid 2934] execve("/bin/cat", ["cat", "/proc/2933/cmdline"], [/* 80 vars */]) = 0 /bin/bash-cecho $$; cat /proc/$$/cmdline[pid 2934] +++ exited with 0 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2934, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 0 +++ $
$$ seems to be cat pid, not bash / sh pid.
In fact, both. bash execve cat , so everyone becomes different.
To understand what exactly is needed for the no-fork behavior, we need to look at the source code. Here is this comment:
Source