I saw this function definition from "Linux Shell Scripting Cookbook", I wonder why there needs two $
sign is needed in the last part of eval $1=\"$2\$\{$1:+':'\$$1\}\"
. How to understand each of the $
sign in entire eval
condition? Thanks!
prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1 ; }
In addition to @tripleee's correct answer, I want to suggest you to try this at command line:
set -- foo bar
echo $1=\"$2\$\{$1:+':'\$$1\}\"
foo="bar${foo:+:$foo}"
As eval
is evil, here is an alternative (but care evil is in details read further!):
prepend() {
[[ -d $2 ]] &&
printf -v "$1" '%s' "$2" "${!1+:}" "${!1}" &&
export "$1"
}
which could be written as oneliner:
prepend() { [[ -d $2 ]]&&printf -v "$1" '%s' "$2" "${!1+:}" "${!1}"&&export "$1";}
Tests:
mkdir /tmp/foo /tmp/bar
prepend myVar /tmp/foo
echo ${myVar@A}
declare -x myVar='/tmp/foo'
prepend myVar /tmp/bar
echo ${myVar@A}
declare -x myVar='/tmp/bar:/tmp/foo'
prepend myVar /tmp/baz
echo ${myVar@A}
declare -x myVar='/tmp/bar:/tmp/foo'
Regarding @jhnc's comment, you could want to sanitize submitted variable name:
Let's try (again):
prepend 'h[`date +%c.%N>/dev/tty`]' /tmp/foo
Mon Nov 25 08:04:26 2024.549285838
Mon Nov 25 08:04:26 2024.552602686
Mon Nov 25 08:04:26 2024.554057179
bash: export: `h[`date +%c.%N>/dev/tty`]': not a valid identifier
Where date
command was exectuted by prepand
function (3 times)!!
To avoid this you may add a little test if stringContain ...
in your command:
prepend() {
case $1 in
*[\`\$]* )
return 1
;;
esac
[[ -d $2 ]] &&
printf -v "$1" '%s' "$2" "${!1+:}" "${!1}" &&
export "$1"
}
In one line:
prepend() { case $1 in *[\`\$]* ) return 1;;esac;[[ -d $2 ]]&&printf -v "$1" '%s' "$2" "${!1+:}" "${!1}"&&export "$1";}
Or two lines:
prepend() { case $1 in *[\`\$]* ) return 1;;esac
[[ -d $2 ]] && printf -v "$1" '%s' "$2" "${!1+:}" "${!1}" && export "$1" ;}
Then
unset myVar
prepend myVar /tmp/foo
echo ${myVar@A}
declare -x myVar='/tmp/foo'
prepend myVar /tmp/bar
echo ${myVar@A}
declare -x myVar='/tmp/bar:/tmp/foo'
prepend myVar /tmp/baz
echo ${myVar@A}
declare -x myVar='/tmp/bar:/tmp/foo'
Upto there, everything look fine. Then finally:
prepend 'h[`date>/dev/tty`]' /tmp/foo
prepend 'h[$(date>/dev/tty)]' /tmp/foo
Nothing! but:
echo $?
1