|
Programming C, bash, Python, Perl, PHP, Java, you name it. |
|
Thread Tools | Display Modes |
|
|||
Dereferencing sh variables
In a Linux Journal Tech tip is shown how you can dereference a variable, when it is passed as string to a function. It uses the bash ! operator.
Code:
DerefernceVariablePassedToFunction() { if [ -n "$1" ] ; then echo "value of [${1}] is: [${!1}]" else echo "Null parameter passed to this function" fi } Variable="LinuxJournal" DerefernceVariablePassedToFunction Variable I just wondered why he did not use eval like this Code:
#/bin/sh dereference() { if [ -n "$1" ] ; then eval echo value of \$1 is: \$$1 else echo "Null parameter passed to this function" fi } variable="Just use 'eval'" dereference variable Code:
sh -vx dereference.sh #/bin/sh dereference() { if [ -n "$1" ] ; then eval echo value of \$1 is: \$$1 else echo "Null parameter passed to this function" fi } variable="Just use 'eval'" + variable=Just use 'eval' dereference variable + dereference variable echo value of $1 is: $variable value of variable is: Just use 'eval' echo value of \$1 is: \$$1into echo value of $1 is: $variable\$1 is seen by the shell as a "$" followed by a '1' . The "\" prevents the shell from interpreting $1 as the first parameter, as it normally would do. \$$1is parsed as a literal "$" followed by the function parameter $1 which contains the string "variable" The second and last pass re-processes this echo value of $1 is: $variableand without any "\" to prevent variable expansion, produces the wanted result: value of variable is: Just use 'eval'
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump |
|
||||
It's linux journal, people assume, who ever said they considered real portability
__________________
My Journal Thou shalt check the array bounds of all strings (indeed, all arrays), for surely where thou typest ``foo'' someone someday shall type ``supercalifragilisticexpialidocious''. |
|
|||
Another demonstration of eval , but where we encounter something strange.
Code:
#!/bin/sh fr_1=un fr_2=deux fr_3=trois nl_1=een nl_2=twee nl_3=drie de_1=eins de_2=zwei de_3=drei one2three() { local LANG LANG="$1" printf "\nCounting in : ${LANG}\n" for nr in 1 2 3 ; do eval printf "-%s" "\$$LANG_$nr" done printf "\n" } #typeset -ft one2three # trace into function (for ksh) one2three nl one2three fr one2three de Code:
$ ./lang-eval Counting in : nl -nl-- Counting in : fr -fr-- Counting in : de -de-- A run with a verbose shell trace shows : Code:
sh -vx lang-eval #!/bin/sh fr_1=un + fr_1=un fr_2=deux + fr_2=deux fr_3=trois + fr_3=trois nl_1=een + nl_1=een nl_2=twee + nl_2=twee nl_3=drie + nl_3=drie de_1=eins + de_1=eins de_2=zwei + de_2=zwei de_3=drei + de_3=drei one2three() { local LANG LANG="$1" printf "\nCounting in : ${LANG}\n" for nr in 1 2 3 ; do eval printf "-%s" "\$$LANG_$nr" done printf "\n" } #typeset -ft one2three # trace into function (for ksh) one2three nl + one2three nl Counting in : nl printf -%s $1 -nlprintf -%s $2 -printf -%s $3 - one2three fr + one2three fr Counting in : fr printf -%s $1 -frprintf -%s $2 -printf -%s $3 - one2three de + one2three de Counting in : de printf -%s $1 -deprintf -%s $2 -printf -%s $3 - Did you ever wonder why shell variables like "$name" are sometimes written as "${name}"? Well the above phenomenom is the reason. The underscore, "_", character is one of the valid characters in a variable name. So the shell seems to interpret "$LANG_", as a variable, which not defined anywhere in the script. We only define "$LANG" as local variable in the shell function, not "$LANG_". The solution is to use the curly braces to explicitly tell the shell where the variable name starts and ends. Code:
eval printf "-%s" "\$${LANG}_$nr" Code:
Counting in : nl -een-twee-drie Counting in : fr -un-deux-trois Counting in : de -eins-zwei-drei Because a "-vx" verbose tracing does not work inside a function we first have to change Code:
#typeset -ft one2three # trace into function (for ksh) Code:
typeset -ft one2three # trace into function (for ksh) Code:
./lang-eval + typeset LANG + LANG=nl + printf \nCounting in : nl\n Counting in : nl + eval printf -%s $nl_1 + printf -%s een -een+ eval printf -%s $nl_2 + printf -%s twee -twee+ eval printf -%s $nl_3 + printf -%s drie -drie+ printf \n + typeset LANG + LANG=fr + printf \nCounting in : fr\n Counting in : fr + eval printf -%s $fr_1 + printf -%s un -un+ eval printf -%s $fr_2 + printf -%s deux -deux+ eval printf -%s $fr_3 + printf -%s trois -trois+ printf \n + typeset LANG + LANG=de + printf \nCounting in : de\n Counting in : de + eval printf -%s $de_1 + printf -%s eins -eins+ eval printf -%s $de_2 + printf -%s zwei -zwei+ eval printf -%s $de_3 + printf -%s drei -drei+ printf \n By using the curly braces "{}" , the shell does not have to guess anymore, which characters exactly make up the variable name end. In most cases it will guess correctly, but in this case it really needs a little help from it's curly friends
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump |
|
||||
I've found it a good habit, to reach for ${} whenever there will be characters intermixed with the variable names, in my scripts, this usually manifests itself as "${ham}/${spam}-${eggs}" and such.
I figure, it beats debugging silly errors if things ever get changed into a situation that needs expicit, or worrying about the possibility of some unexpected variable slipping into the execution environment later, and changing the implied behaviour. Sometimes code that is explicit is better documentation then a comment.
__________________
My Journal Thou shalt check the array bounds of all strings (indeed, all arrays), for surely where thou typest ``foo'' someone someday shall type ``supercalifragilisticexpialidocious''. |
Tags |
bash ! operator, curly braces, dereference, eval, variable name |
Thread Tools | |
Display Modes | |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
passing make args/variables to builds of prerequisite ports | jbhappy | FreeBSD Ports and Packages | 2 | 18th July 2008 02:35 PM |