12

I know that this may sound as "not as intended by designer" but I have real life situation where a bash script I am modifying needs to call another bash script that I am not allowed to modify.

That "unmodifiable bash script" starts with:

source `dirname $0`/setenv.sh

(that setenv.sh also starts with SCR2PATH=source "$( cd "$(dirname "$0")" ; pwd -P )" and is also unmodifiable)

Is there a trick in which I can fool the child script with a different $0 than that of the calling script?

  • 4
    Is the unmodifiable child script sourced or called? – icarus Dec 25 '19 at 15:05
  • 2
    What are you trying to achieve? What value do you want $0 to have? Can you show us the script you can actually modify? What is the source "$( cd "$(dirname "$0")" ; pwd -P )" supposed to do? That will attempt to source a directory, you should be getting an error. – terdon Dec 25 '19 at 15:08
  • 8
    @datsb so, you want one script you don't show us to source another script you don't show us which sources a third one which you also don't show us? I hope you can see how this is a little difficult to understand ;) Please edit your question and add the scripts. The best thing would be to make tiny, simple scripts that recreate the problem and show us those. – terdon Dec 25 '19 at 20:07
  • 3
    the execve system call allows setting $0 to any arbitrary value you just need a way to exploit fhat from inside your script. – Jasen Dec 25 '19 at 23:25
  • 4
    @jasen that would not work for a bash script. Bash needs to be invoked with a correct path for the script so it can load and interpret it. It is bash, not the operating system that sets $0 for the script. – Philip Couling Dec 26 '19 at 0:41
18

Maybe this will do:

bash -c '. /path/to/unmodifiable' /fake/path args ...

Obviously, /path/to/unmodifiable should be a shell script; this silly trick won't work with other kind of executables. This also won't work with zsh (but will work with other shells like dash, ksh, etc).

If you have to source instead of call the unmodifiable script, you can use the same trick from a wrapper calling your outer script, or have it re-call itself:

$ cat unmodifiable
#! /bin/sh
printf '{%s} ' "$0" "$@"
echo

$ cat becoming
#! /bin/sh
[ "$MYSELF" ] || MYSELF=$0 exec sh -c '. "$MYSELF"' "I'm the mountain!" "$@"
. ./unmodifiable

$ chmod 755 becoming
$ ./becoming 1 2 3
{I'm the mountain!} {1} {2} {3}
| improve this answer | |
  • Your bash -c '. /path/to/unmodifiable' /fake/path args ... trick works like a charm. – datsb Dec 26 '19 at 8:27
19

You cannot "fool" the child script, but you can call it via a different name by creating a symlink to the called script and calling the symlink. This will, I believe achieve the objective you are looking for.

Example:

$ cat ./bin/script.sh
echo $0

$ ./bin/script.sh
./bin/script.sh
$ ln -s bin/script.sh foo.sh
$ ./foo.sh
./foo.sh
| improve this answer | |
  • I may have described my objective unclearly: foo.sh is in the directory that I need to be returned by dirname. script.sh (which calls foo.sh) is in a different directory. When script.sh calls foo.sh (using source), the dirname $0 in foo.sh reports script.sh's directory, not foo.sh's -- which is exactly the opposite of what's needed. – datsb Dec 25 '19 at 19:46
  • 1
    so symlink it into the directory you want... assuming that directory is writable by you. If it is not, then I think you're out of luck :( – sitaram Dec 26 '19 at 1:09
0

You can use exec -a in a subshell: (exec -a fakeDollarZero /unmodifiable/bash/script the rest of the args)

Unlike mosvy's answer, this would work even if it were something other than a bash script.

| improve this answer | |
  • this does not work with executable scripts (no matter the language they're written in), but only with binaries. – mosvy Jan 16 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.