Yes - the $0 variable gives the name of the script as it was run:
$ cat example.sh
#!/bin/bash
script_name=$( basename ${0#-} ) #- needed if sourced no path
this_script=$( basename ${BASH_SOURCE} )
if [[ ${script_name} = ${this_script} ]] ; then
echo "running me directly"
else
echo "sourced from ${script_name}"
fi
$ cat example2.sh
#!/bin/bash
. ./example.sh
Which runs like:
$ ./example.sh
running me directly
$ ./example2.sh
example.sh sourced from example2.sh
That doesn't cater for being source from an interactive shell, but you get this idea (I hope).
Updated to include BASH_SOURCE - thanks h.j.k
you should handle that stuff in the index evals. and you can indirect through your indirection variable's indices if you make it an array.
a=(abc1 def2 ghi3 jkl4 mno5)
r=('a[c=${#a[@]}]' a\[i] a\[@])
for i in 0 1 2 3 4 5
do c=
printf "<%s>\n" "${!r-${!r[i<c?1:2]}}"
printf "\n\tindex is $i and count is $c\n\n"
done
<abc1>
index is 0 and count is 5
<def2>
index is 1 and count is 5
<ghi3>
index is 2 and count is 5
<jkl4>
index is 3 and count is 5
<mno5>
index is 4 and count is 5
<abc1>
<def2>
<ghi3>
<jkl4>
<mno5>
index is 5 and count is 5
Because bash
's indices are 0-based, the total count of array objects will always work out to one more than than the highest set index, and so:
c=
echo "${a[c=${#a[@]}]-this index is unset}" "$c"
this index is unset 5
...the parameter expands out to the default word if any is provided.
If one is not provided:
c=
${!r}
echo "$c"
5
...there's no harm done.
In the loop I track an $i
ndex variable and check if it is at least as large as $c
ount. When it is lesser I expand the $r
eference var to a[i]
because it is a valid index, but when it is equal or greater I expand the $r
ef to the entire $a
rray.
Here it is in a function:
ref_arr(){
local index=-1 count=
local ref=( "$1[ count= \${#$1[@]} ]"
"$1[ index ]" "$1[ @ ]"
) && printf "input array '%s' has '%d' members.\n" \
"$1" "${!ref-${count:?invalid array name: "'$1'"}}"
while [ "$((index+=1))" -lt "$count" ]
do printf "$1[$index] == '%s'\n" "${!ref[1]}"
done
}
some_array=(some "dumb
stuff" 12345\'67890 "" \
'$(kill my computer)')
ref_arr some_array
ref_arr '$(echo won'\''t work)'
input array 'some_array' has '5' members.
some_array[0] == 'some'
some_array[1] == 'dumb
stuff'
some_array[2] == '12345'67890'
some_array[3] == ''
some_array[4] == '$(kill my computer)'
bash: count: invalid array name: '$(echo won't work)'
Best Answer
eval "$1"
executes the command in the current script. It can set and use shell variables from the current script, set environment variables for the current script, set and use functions from the current script, set the current directory, umask, limits and other attributes for the current script, and so on.bash -c "$1"
executes the command in a completely separate script, which inherits environment variables, file descriptors and other process environment (but does not transmit any change back) but does not inherit internal shell settings (shell variables, functions, options, traps, etc.).There is another way,
(eval "$1")
, which executes the command in a subshell: it inherits everything from the calling script but does not transmit any change back.For example, assuming that the variable
dir
isn't exported and$1
iscd "$foo"; ls
, then:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
lists the content of/somewhere/else
and prints/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
lists the content of/somewhere/else
and prints/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
lists the content of/starting/directory
(becausecd ""
doesn't change the current directory) and prints/starting/directory
.