What does the substitution ${!var_name+x} mean?

Multi tool use
I found a script that has a function that checks if a variable is set but i don't understand it very well.
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
What exactly happens with this substitution ?
bash shell-script variable-substitution
add a comment |
I found a script that has a function that checks if a variable is set but i don't understand it very well.
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
What exactly happens with this substitution ?
bash shell-script variable-substitution
related ${!FOO} and zsh.
– αғsнιη
10 hours ago
add a comment |
I found a script that has a function that checks if a variable is set but i don't understand it very well.
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
What exactly happens with this substitution ?
bash shell-script variable-substitution
I found a script that has a function that checks if a variable is set but i don't understand it very well.
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
What exactly happens with this substitution ?
bash shell-script variable-substitution
bash shell-script variable-substitution
asked 11 hours ago


Karim ManaouilKarim Manaouil
1919
1919
related ${!FOO} and zsh.
– αғsнιη
10 hours ago
add a comment |
related ${!FOO} and zsh.
– αғsнιη
10 hours ago
related ${!FOO} and zsh.
– αғsнιη
10 hours ago
related ${!FOO} and zsh.
– αғsнιη
10 hours ago
add a comment |
1 Answer
1
active
oldest
votes
In the bash
shell, ${!var}
is a variable indirection. It expands to the value of the variable whose name is kept in $var
.
The variable expansion ${var+value}
is a POSIX expansion that expands to value
if the variable var
is set (no matter if its value is empty or not).
Combining these, ${!var+x}
would expand to x
if the variable whose name is kept in $var
is set.
Example:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(empty line as output)
The function in the question could be shortened to
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
or even:
check_if_variable_is_set () { [ -v "$1" ]; }
or even:
check_if_variable_is_set()[[ -v $1 ]]
Where -v
is a bash
test on a variable name which will be true if the named variable is set, and false otherwise.
POSIXly, it could be written:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Note that all those are potential command injection vulnerabilities if the argument to that function could end up being under control of an attacker. Try for instance with check_if_variable_is_set 'a[$(id>&2)]'
.
To guard against that, you may want to verify that the argument is a valid variable name first. For variables:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(note that [[:alpha:]]
will check for alphabetical characters in your locale while some shells only accept alphabetical characters from the portable character set in their variable)
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f501368%2fwhat-does-the-substitution-var-namex-mean%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
In the bash
shell, ${!var}
is a variable indirection. It expands to the value of the variable whose name is kept in $var
.
The variable expansion ${var+value}
is a POSIX expansion that expands to value
if the variable var
is set (no matter if its value is empty or not).
Combining these, ${!var+x}
would expand to x
if the variable whose name is kept in $var
is set.
Example:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(empty line as output)
The function in the question could be shortened to
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
or even:
check_if_variable_is_set () { [ -v "$1" ]; }
or even:
check_if_variable_is_set()[[ -v $1 ]]
Where -v
is a bash
test on a variable name which will be true if the named variable is set, and false otherwise.
POSIXly, it could be written:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Note that all those are potential command injection vulnerabilities if the argument to that function could end up being under control of an attacker. Try for instance with check_if_variable_is_set 'a[$(id>&2)]'
.
To guard against that, you may want to verify that the argument is a valid variable name first. For variables:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(note that [[:alpha:]]
will check for alphabetical characters in your locale while some shells only accept alphabetical characters from the portable character set in their variable)
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
add a comment |
In the bash
shell, ${!var}
is a variable indirection. It expands to the value of the variable whose name is kept in $var
.
The variable expansion ${var+value}
is a POSIX expansion that expands to value
if the variable var
is set (no matter if its value is empty or not).
Combining these, ${!var+x}
would expand to x
if the variable whose name is kept in $var
is set.
Example:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(empty line as output)
The function in the question could be shortened to
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
or even:
check_if_variable_is_set () { [ -v "$1" ]; }
or even:
check_if_variable_is_set()[[ -v $1 ]]
Where -v
is a bash
test on a variable name which will be true if the named variable is set, and false otherwise.
POSIXly, it could be written:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Note that all those are potential command injection vulnerabilities if the argument to that function could end up being under control of an attacker. Try for instance with check_if_variable_is_set 'a[$(id>&2)]'
.
To guard against that, you may want to verify that the argument is a valid variable name first. For variables:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(note that [[:alpha:]]
will check for alphabetical characters in your locale while some shells only accept alphabetical characters from the portable character set in their variable)
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
add a comment |
In the bash
shell, ${!var}
is a variable indirection. It expands to the value of the variable whose name is kept in $var
.
The variable expansion ${var+value}
is a POSIX expansion that expands to value
if the variable var
is set (no matter if its value is empty or not).
Combining these, ${!var+x}
would expand to x
if the variable whose name is kept in $var
is set.
Example:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(empty line as output)
The function in the question could be shortened to
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
or even:
check_if_variable_is_set () { [ -v "$1" ]; }
or even:
check_if_variable_is_set()[[ -v $1 ]]
Where -v
is a bash
test on a variable name which will be true if the named variable is set, and false otherwise.
POSIXly, it could be written:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Note that all those are potential command injection vulnerabilities if the argument to that function could end up being under control of an attacker. Try for instance with check_if_variable_is_set 'a[$(id>&2)]'
.
To guard against that, you may want to verify that the argument is a valid variable name first. For variables:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(note that [[:alpha:]]
will check for alphabetical characters in your locale while some shells only accept alphabetical characters from the portable character set in their variable)
In the bash
shell, ${!var}
is a variable indirection. It expands to the value of the variable whose name is kept in $var
.
The variable expansion ${var+value}
is a POSIX expansion that expands to value
if the variable var
is set (no matter if its value is empty or not).
Combining these, ${!var+x}
would expand to x
if the variable whose name is kept in $var
is set.
Example:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(empty line as output)
The function in the question could be shortened to
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
or even:
check_if_variable_is_set () { [ -v "$1" ]; }
or even:
check_if_variable_is_set()[[ -v $1 ]]
Where -v
is a bash
test on a variable name which will be true if the named variable is set, and false otherwise.
POSIXly, it could be written:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Note that all those are potential command injection vulnerabilities if the argument to that function could end up being under control of an attacker. Try for instance with check_if_variable_is_set 'a[$(id>&2)]'
.
To guard against that, you may want to verify that the argument is a valid variable name first. For variables:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(note that [[:alpha:]]
will check for alphabetical characters in your locale while some shells only accept alphabetical characters from the portable character set in their variable)
edited 9 hours ago


Stéphane Chazelas
306k57577931
306k57577931
answered 11 hours ago


KusalanandaKusalananda
131k17249408
131k17249408
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
add a comment |
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
There is nothing on earth more complete than this. You deserve a cookie for that.
– Karim Manaouil
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
@KarimManaouil A third of that cookie goes to Stéphane though :-)
– Kusalananda
8 hours ago
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f501368%2fwhat-does-the-substitution-var-namex-mean%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
tXsy4Nh,FwjDWhH8O4 6Q8sNbNgJ5 4maFzFgLxLi,xNBhOEvg10,p72h02sVh
related ${!FOO} and zsh.
– αғsнιη
10 hours ago