16

Is there any way I can print the variable name along with its value?

j=jjj
k=kkk
l=lll

for i in j k l
do
    ....
done

Expected output (each variable on a separate line):

j = jjj 
k = kkk
l = lll

Can any one suggest a way to get the above result?

1

5 Answers 5

28

A simple way in Bash:

j="jjj"
k="kkk"
l="lll"

for i in j k l; do echo "$i = ${!i}"; done

The output:

j = jjj
k = kkk
l = lll

  • ${!i} - Bash variable expansion/indirection (gets the value of the variable name held by $i)
3
  • 2
    You can make {j,k,l} short with {j..l} also : ) Oct 12, 2017 at 3:25
  • @αғsнιη, it's reasonable for extended ranges, as long as there only 3 items - {j,k,l} would be enough Oct 12, 2017 at 8:30
  • 1
    j k l would be enough. Oct 12, 2017 at 11:43
9

If you have bash v4.4 or later you can use ${VAR@A} Parameter expansion operator.

This is discussed in the Bash manual under section 3.5.3 Shell Parameter Expansion

'A' Operator

The expansion is a string in the form of an assignment statement or declare command that, if evaluated, will recreate parameter with its attributes and value.

So with this you can do:

j="jjj"
k="kkk"
l="lll"

for i in {j,k,l}; do 
    echo "${!i@A}"
done

And your result should be:

j='jjj'
k='kkk'
l='lll'
2
  • 1
    When the variable is declared from outside the script it will be printed as declare -x NAME='value'
    – user149244
    Feb 26, 2021 at 11:26
  • Adding on the comment from @user149244 : happens for example if you source some variables from another file, so they won't print like the others.
    – Lenormju
    Sep 6, 2022 at 6:26
6

Or in ksh, zsh, bash or yash use typeset -p. In zsh and when in the global scope, you can also use typeset alone if you don't care about seeing the type:

% j=jjj; k=kkk; l=(l l l)               
% for v in j k l; do typeset -p "$v"; done
typeset j=jjj
typeset k=kkk
typeset -a l=( l l l )

(zsh only):

% typeset j k l
j=jjj
k=kkk
l=( l l l )

In zsh, the variant with -p won't show the value of variables with the hideval flag (as set with typeset -H as is the case for some special parameters).

zsh can also print the definition of variables that match a pattern with typeset -m (and that also works in functions or if the typesetsilent option is set):

$ typeset -m '[j-l]'
j=jjj
k=kkk
l=( l l l )
1
  • 4
    works with Bash too
    – Zombo
    Oct 11, 2017 at 23:48
3

Whilst ${!i} is a cleaner and faster solution, for completeness, the indirect reference can also be obtained with the following example:

 foo=bar
 bar=baz
 $ echo $foo
 bar
 $ eval echo \$${foo}
 baz

Therefore:

 j="jjj"
 k="kkk"
 l="lll"

 for i in {j,k,l}; do
   echo "$i = `eval echo \\$${i}`"
 done

Gives:

 j = jjj
 k = kkk
 l = lll

References:

Indirect References

1

In standard sh syntax, that'd be:

j=jjj
k=kkk
l=lll

for i in j k l
do
    eval 'printf "%s\n" "$i=${'"$i"'}"'
done

That is ask the shell to interpret as shell code the concatenation of printf "%s\n" "$i=${ with the expansion of $i and }", so for instance for i=j, it interprets:

printf "%s\n" "$i=${j}"

Which once evaluated calls the printf command with %s\n and j=jjj as arguments.

The curly braces are necessary in some shells for values of i such as 10 where $10 would be interpreted as ${1}0 in some shells instead of ${10}.

Beware that with j='foo; bar', you'd see i=foo; bar as output. If you wanted to output the shell code that would be used assign the same value to j (like typeset -m j does in zsh), POSIXly, you could do:

show_var() (
  for _var do
    eval 'set -- "$@" "$_var" "${'"$_var"'}"'
    shift
  done
  LC_ALL=C awk -v q="'" -- '
    function shquote(s) {
      gsub(q, "&\\\\&&", s)
      return q s q
    }
    BEGIN {
      for (i = 1; i < ARGC; i++) print ARGV[i]"="shquote(ARGV[++i])
    }' "$@"
)

And then:

show_var j k l

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .