![Creative The name of the picture]()

Clash Royale CLAN TAG#URR8PPP
Checking if current file is being sourced using return yields reversed result after command returning 1
I know the title is a bit weird, but I'm not sure how to better word it.
I'm using $(return &> /dev/null) to detect if a file is sourced or not.
$(return &> /dev/null)
I know that this method is not 100% reliable, but it has worked for me without issues before now. I've figured out how to work around the problem, but I can't figure out why this is happening.
Edit: This is for an internal company project and is not intended to be POSIX compliant or portable to other shells.
I've tried this on three different systems and had the same results:
Redhat 6.9; $BASH_VERSION=4.1.2(1)-release
Mint 18.2; $BASH_VERSION=4.3.48(1)-release
Arch; $BASE_VERSION=4.4.23(1)-release
If $? is 1 (false) when $(return &> /dev/null) the return code is reversed.
$?
$(return &> /dev/null)
$ hr | cat test_0source - test_0source.sh; hr; ./test_0source
#!/bin/bash
# test_0source
false
test_0source.sh
false
source test_0source.sh
true
test_0source.sh
true
source test_0source.sh
========================================
#!/bin/bash
# test_0source.sh
# shellcheck disable=SC2091
$(return &> /dev/null)
echo "$?"
========================================
1
1
1
0
I expected to be seeing
1
0
1
0
My workaround is to add true right before the return check. While this gives me the correct results, adding false instead of true cause the return check to always return 1.
true
return
false
true
return
I realize I'm missing something basic here, but I'm not seeing it. Why is this doing this?
Edit: I had an incorrect value for $? in my initial explanation above.
Update:
First, using $(return 0 &> /dev/null) resolves the problem, thanks to @ondre-k.
$(return 0 &> /dev/null)
Ondre also pointed out that comparing BASH_SOURCE against $0 is a more idiomatic way to do this:
$ hr | cat test_0bs - test_0bs.sh; hr; test_0bs | less
#!/bin/bash
# test_0bs
false
test_0bs.sh
hr
false
source test_0bs.sh
hr
true
test_0bs.sh
hr
true
source test_0bs.sh
========================================
#!/bin/bash
# test_0bs.sh
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
echo "We are not being sourced."
else
echo "We are being sourced."
fi
========================================
We are not being sourced.
========================================
We are being sourced.
========================================
We are not being sourced.
========================================
We are being sourced.
I suspect there may be an edge case or two around this, but it also seems to me that these cases will be less of a concern.
[[ "${BASH_SOURCE}" = ${0} ]]
0
1
bash
. file-to-source || { echo "source failed." >&2"; exit 1; }
source
'.'
${BASH_SOURCE}
BASH
1 Answer
1
What you are doing is basically "abusing" the fact that return can only happen from function or a sourced script and assuming it yields 0 when a return was possible (we're sourced) and 1 if not, while suppressing the error output. You also do that in a subshell. Oddly enough, bash is still OK with placement of the return but does not return from a sourced script and keeps going. So far, so god.
0
1
return
The problem is, that "naked" (w/o explicit value specified) return, just like exit propagate last seen return code (return code of the command immediately preceding it).
return
exit
In other words false; return would be the same thing as return 1. You can also try this out by replacing true and false by (exit 255) and see what happens. The 1 you are seeing for return following a false is not the one of "error: you cannot say return now" as your test is looking for, but just an ordinary return that has returned the last from the command preceding it (false). This difference would also become obvious if you've dropped the stderr redirection.
false; return
return 1
true
false
(exit 255)
1
return
return
return
false
stderr
TL;DR for this construct to work as you expected, change it to return 0.
return 0
I hope I have not missed some corner case, but this should work as an alternative with bash by comparing name of the executed script and a source file. [[ "${BASH_SOURCE}" = ${0} ]] evaluates to 0 if file has not been sourced and 1 if it has. Or replace = with != to get same meaning of values as in the return case above.
[[ "${BASH_SOURCE}" = ${0} ]]
0
1
=
!=
return
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
May I interest you in an alternative method?
[[ "${BASH_SOURCE}" = ${0} ]]evaluates to0if file is not source and1if it is (test for not equal if you prefer it the other way around). Should run onbashpretty much anywhere.– Ondrej K.
yesterday