I've found some existing code that will break if words in ${BASH_SOURCE[@]} don't match the filepath given to '.' or 'source': [[ ${BASH_ARGV[0]} = "${BASH_SOURCE[0]}" ]] which is part of a test to determine whether any args were provided after "source filename".
I use this at the end of my file called «autoload.bash», which after defining a function called «autoload», has: if [[ -n "$*" ]] && ! { > (( BASH_ARGC[0] == 1 )) && [[ ${BASH_ARGV[0]} = "${BASH_SOURCE[0]}" ]] > || > (( BASH_ARGC[0] == 0 && ${#BASH_ARGC[@]} > 0 )) # in case this gets > fixed sometime > } > then > autoload -- "$@" > fi This is trying to figure out whether any arguments were provided after: . "$path/autoload.bash" > It can't simply look at "$@" because when *no* args are given, the outer args are left bound to "$@" (and can be modified by shift & set). But unfortunately in this case, BASH_ARGC[0] is 1 rather than 0,, and the filename provided to "source" (now ${BASH_SOURCE[0]}) is prepended to BASH_ARGV. That's where the test for BASH_SOURCE[0] == BASH_ARGV[0] is needed. It's still only probabilistic, because BASH_ARGV & BASH_ARGC have some other weird behaviours, but it has a higher likelihood of being correct, and in the cases where it's giving a false nagative, the parameters would be invalid for my use case. This test will clearly break if BASH_SOURCE does not contain exactly the parameter given to "source" (or "."). However this kludge is only necessary because of the pollution of BASH_ARGC/BASH_ARGV, and my test will work correctly if that pollution is removed. I would be happy to always have $(realpath $0) or $(realpath $sourced_filename) in BASH_SOURCE if there was also a concomitant change to preface '0' onto ARGC (and not change BASH_ARGV) when a file is sourced (or a function is called) without any args. However I worry that the latter change might adversely affect someone else's code. -Martin On Thu, 27 Jun 2024 at 00:17, Martin D Kealey <mar...@kurahaupo.gen.nz> wrote: > > > On Wed, 26 Jun 2024, 03:14 Chet Ramey, <chet.ra...@case.edu> wrote: > >> On 6/19/24 6:12 PM, konsolebox wrote: >> >> > Alternatively, have BASH_SOURCE always produce real physical paths >> > either by default or through a shopt. >> >> This is the best option. I don't think changing bash to do this by >> default would have negative side-effects. >> > > Just to be clear, would this result in $0 and ${BASH_SOURCE[@]:(-1):1} > potentially yielding different values? > > (I would certainly hope so, otherwise how would we be able to alter the > behaviour of a script based on the name used to invoke it? And before > anyone tells me what a bad idea that would be, sometimes it's necessary to > mimic historical behaviour such as gzip vs gunzip, and there are definitely > scripts out there that rely on this.) > > However I do see a minor downside: looking at BASH_SOURCE to decide > whether a given ancestor in the call chain is actually $0, the naive string > comparison will now fail. This isn't important to most programs, but may be > necessary for, say, a debugging framework. > > I have a small pure-Bash library that mimics Perl's "Carp.pm", providing > "carp" , "cluck", "croak", and "confess". One feature I'm in the process of > adding is suppression of specific "modules" from the backtrace displayed > after a message; in this context I equate "module" with "source file". > > Since this is new for me, I can just document that users must use > ${BASH_SOURCE[@]:(-1):1} rather than $0 when asking my "Carp" module to > exclude its own "main" from backtraces. > > But if someone else has already implemented this, then their code will be > subtly broken by this proposed change to Bash. > > -Martin > >>