I was trying to craft a script that produces the location of the local bash binary from a variety of (Linux) environments, assuming existence of standard shell /bin/sh and that /usr/bin/env bash is capable of finding it. Once I obtain the bash shell, the next step is naturally to attempt to find the shell's own path. Disappointingly, I wasn't able to get $SHELL to produce the binary path, so I decided to attempt to get the bash pid path from proc as so:
#!/bin/sh
/usr/bin/env -i /usr/bin/env bash -c '/usr/bin/env readlink /proc/$$/exe'
Strangely, this returns /usr/bin/readlink.
Just as I was about to give up, I tried fiddling like so:
#!/bin/sh
/usr/bin/env -i /usr/bin/env bash -c '/usr/bin/env readlink /proc/$$/exe; true'
/usr/bin/bash Somehow, this works!
Why does this work? What is the difference between the two invocations?
EDIT:
Many of you are confused by my /usr/bin/env invocations. As I explain, restricted PATHs prevent a regular env bash invocation from finding bash, and I don't need a current bash path, just a bash path. My script is tested and works, whereas your "fixed" versions don't work for my PATHs. Anyways, that is not the crux of the question.
Let me put a copy of my comment here:
Just to explain about the script, I'm not trying to find the bash executable previously being used; I'm not assuming I'm running in bash, rather I'm finding a valid bash executable path. It relies on the /usr/bin/env bash trick being able to find bash in basically all systems. The reason for the first /usr/bin/env -i being, this needs to run in locked-off PATHs which actually prevent env from finding bash, which removing the environment does allow finding, as I tested. The last env is due to having no PATH, readlink cannot be found... except with env.
You may notice that I run in /bin/sh, careful to not assume the bash path or that I'm running in bash already.
EDIT:
I'm going with
#!/bin/sh
/usr/bin/env -i bash -c 'echo $BASH'
env -i, you explicitly say "well, don't use the$PATHas set for this process, use something else, as used by nothing started in this environment", so this is a non-starter to find the actual bash executable used in the actual environment./usr/bin/envfrom/usr/bin/env -i? What sense does that make? And then you start bash, just to again start/usr/bin/env? So now we're threeenvdeep, and the only one of these that actually does anything does the opposite of what you want./proc/$$is totally unnecessary, Linux (and you say only care about Linux, but as far as I'm aware, all other Unixoid OSes with /proc probably do the same) offers/proc/self. You could simply ask bash itself instead of going literally four redirections there.;truechanges things is explained for example here (if there's only a single command, the shell and env, can, instead of forking and replacing the fork with the execution of the launched command, just replace itself with the launched command.