Reputation: 6769
MOST ANSWERS I FOUND ON HERE ONLY SEEM TO WORK FOR /bin/bash
.
Tricks like $BASH_SOURCE
and $SHLVL
don't seem to be working with sh
.
There was an answer which asked to use return
, because it only works within functions and sourced scripts, and see if it generated any error but I didn't understand why on executing return
on command-line I got logged out of the shell. If I "executed or sourced" a script containg return
, it just exits that script. This was happening when I was on freebsd
. Also I don't use any desktop environment there.
Simply typing on command line,
return
result: logged out
Executing or sourcing a script containing return
:
$ cat testscript
#! /bin/sh
echo hello
return
echo hello
$ ./testscript
hello
$ . testscript
hello
$
This wasn't the case when I did the same on macOS
(executed /bin/sh first). It worked perfectly fine there. There it just said
sh: return: can only `return' from a function or sourced script
just as expected.
I am looking for a solution to detect if a script is sourced in case of /bin/sh
.
I am using freebsd
and there I currently have default shell set to sh
. I know I can install bash
, but still I want to know how can I do the same for /bin/sh
.
I would like to mention a little more detail.
In macOS
I tried starting /bin/sh
through command line, and I realised later that it is a non-login shell. So, when I types in logout
there, reusult was:
sh: logout: not login shell: use `exit'
So I made /bin/sh
my default shell and I am sure enough that /bin/sh
was executed. When I typed in return
there, the output I got is:
sh: return: can only `return' from a function or sourced script
Again just as expected. But when I typed, echo $SHELL
, output was:
/bin/bash
And I checked /bin
directory of of my machine and /bin/sh
and /bin/bash
don't seem to be linked.
Now I tried executing /bin/sh
there as well. The results were as follows:
$ /bin/sh
$ return
$ return
logged out on 2nd return
So in simple language it doesn't show any output if /bin/sh
is a non-login shell and simply just exits that shell.
@user1934428 gave some nice amount of information in @CharlesDuffy 's answer. It's worth giving a read.
There he mentions that FreeBSD
manual has no documentation for return
statement.
sh man page, FreeBSD
I checked if OpenBSD has the same case for man page, but it did define return
as:
return [n] Exit the current function or . script with exit status n, or that of the last command executed.
One other issue is most man pages show bash
manual on asking for man sh
. Idk if its supposed to be like that or no.
Also, can someone suggest if I should start a new question for undefined behaviour of return
? Because I think this question has went really off-topic. Not sure if it would be a good idea to do so.
Upvotes: 2
Views: 1622
Reputation: 6769
I found the answer to this through FreeBSD mailing lists.
The man page where the entry for return
was missing was the wrong man page.
Looking at the correct man page, the complete behaviour of return
statement has been stated.
The syntax of the return command is
return [exitstatus]
It terminates the current executional scope, returning from the closest
nested function or sourced script; if no function or sourced script is
being executed, it exits the shell instance. The return command is im-
plemented as a special built-in command.
As suggested by Ian in mailing lists, in case of /bin/sh
a good possible way seems to keep a fixed name for your script and expand $0
:
${0##*/}
and match it with the name. If the expansion produces anything else, it means script has been sourced. Another case could be that the user renamed it. So it's not completely error-prone but still should get my job done.
Upvotes: 1
Reputation: 2601
If you plan to use Bourne shell (/bin/sh) only testing $0 works nice.
$ cat t
#!/bin/sh
if [ $0 == "sh" ]; then
echo "sourced"
else
echo executed
fi
$ . t
sourced
$ . ./t
sourced
$ ./t
executed
$ sh t
executed
$ sh ./t
executed
If you want to call or source the script from other shells test $0 against list of shell names.
As @Mihir pointed FreeBSD shell works as described in manual page sh(1). In MacOS /bin/sh is basically bash albeit files /bin/sh and /bin/bash slightly differ. Note that comand man sh on Mac brings manual page for bash
Upvotes: 0
Reputation: 295373
$ sh ./detect-sourcing.sh
We were executed
$ sh -c '. ./detect-sourcing.sh'
We were sourced
#!/bin/sh
if (return 2>/dev/null); then
echo "We were sourced"
else
echo "We were executed"
fi
I haven't analyzed whether this is strictly required by the POSIX sh standard, but it works with /bin/sh
on MacOS, the OP's stated platform.
Upvotes: 3