8

I want to write function (let's call it superEcho) that takes a variable name as input. The function should print that variable's name and its value

function superEcho
{
     echo "$1: ?????"
}

var=100

superEcho var

I want this script to return

var: 100

But I don't know what should I put instead of "?????" in the superEcho function.

8

POSIXly:

superEcho() {
  eval 'printf "%s\n" "$1: ${'"$1"'}"'
}

Like for the bash-specific ${!var}, that expects $1 has been sanitized and contains a valid variable name. Otherwise, that amounts to an arbitrary command injection vulnerability.

You could do the sanitization in the function:

superEcho() {
  case $1 in
    ("" | *[!_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]* | [0123456789]*)
      printf >&2 'Invalid variable name: "%s"\n' "$1"
      return 1;;
    (*) eval 'printf "%s\n" "$1: ${'"$1"'}"'
  esac
}

Note that for variables of type array or associative array, in bash or ksh (POSIX sh has no array except "$@" which you couldn't use here as that would be the arguments of the superEcho function itself) that only prints the value of the element of indice 0, while in zsh, that would output the concatenation of the values with the first character of $IFS (and with SPC characters in yash).

In ksh, zsh, bash or yash (the 4 Bourne-like shells with array support). See also typeset -p var to print the definition and attributes of a variable.

4
  • Any particular reason why you have to list out the 26 times 2 alphabets? When the range 0-9 is understood then why not a-z ?
    – user218374
    Mar 10 '17 at 12:02
  • @Rakesh, [a-z] is locale-dependant and generally includes a lot more than those 26 characters (and the POSIX spec and most (though not all) shells won't have those in variable names). Alternative would be to start a subshell and have export LC_ALL=C in it. Mar 10 '17 at 12:11
  • @Rakesh, POSIX doesn't guaranteed that 0-9 only matches 0123456789 either (except in the C/POSIX locale of course), but in practice it does. I'd consider broken a locale where that's not the case. Mar 10 '17 at 12:18
  • @Rakesh I've now realised that many locales on many systems were "broken" in that regard and changed it to 0123456789 Sep 15 '20 at 10:04
2

Use ${!variablename}:

function superEcho
{
    printf '%s: %s\n' "$1" "${!1}"
}
1
  • 1
    Please disregard my previous (now deleted) comment if you happened to see it. I was being silly.
    – terdon
    Mar 10 '17 at 11:10
1

I do it another way around. I often want to use the variable name for e-mails, logs or flags (written to the disk) so that everything belonging to one device is named the same way - using the variable name as the base.

RPiZero=10

ReadRPiTemp ()
{
    eval ReadSegment='$'$1
    echo "variable content: $ReadSegment"
    echo "variable name: $1"
}

ReadRPiTemp RPiZero
# NOT ReadRPiTemp "$RPiZero"

Above will work in sh and bash. As I need to be compatible with sh in my work, I neglected to mention a proper way to do the same in Bash.

RPiZero=10

ReadRPiTemp ()
{
    declare -n ReadSegment=$1
    echo "variable content: $ReadSegment"
    echo "variable name: $1"
}

ReadRPiTemp RPiZero
# NOT ReadRPiTemp "$RPiZero"

Both of the above will print out the same:

variable content: 10
variable name: RPiZero

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.