Automatic variable expansion inside bash [[ ]] command
When dereferencing a variable in bash
, you have to use $
sign. Nevertheless, it seems that the following is working just fine:
x=5
[[ x -gt 2 ]]
Can anybody explain this?
Edit: (more info)
What I mean is how and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is evaluated to false (return status 1)
bash bash-expansion
add a comment |
When dereferencing a variable in bash
, you have to use $
sign. Nevertheless, it seems that the following is working just fine:
x=5
[[ x -gt 2 ]]
Can anybody explain this?
Edit: (more info)
What I mean is how and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is evaluated to false (return status 1)
bash bash-expansion
2
What do you mean by "working just fine"? And does your assessment change if you dox=1
followed by[[ x -gt 2]]
?
– nohillside
Dec 3 '18 at 21:01
I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)
– Guest
Dec 3 '18 at 21:13
add a comment |
When dereferencing a variable in bash
, you have to use $
sign. Nevertheless, it seems that the following is working just fine:
x=5
[[ x -gt 2 ]]
Can anybody explain this?
Edit: (more info)
What I mean is how and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is evaluated to false (return status 1)
bash bash-expansion
When dereferencing a variable in bash
, you have to use $
sign. Nevertheless, it seems that the following is working just fine:
x=5
[[ x -gt 2 ]]
Can anybody explain this?
Edit: (more info)
What I mean is how and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is evaluated to false (return status 1)
bash bash-expansion
bash bash-expansion
edited Dec 4 '18 at 1:11
Isaac
11.6k11752
11.6k11752
asked Dec 3 '18 at 20:47
GuestGuest
593
593
2
What do you mean by "working just fine"? And does your assessment change if you dox=1
followed by[[ x -gt 2]]
?
– nohillside
Dec 3 '18 at 21:01
I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)
– Guest
Dec 3 '18 at 21:13
add a comment |
2
What do you mean by "working just fine"? And does your assessment change if you dox=1
followed by[[ x -gt 2]]
?
– nohillside
Dec 3 '18 at 21:01
I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)
– Guest
Dec 3 '18 at 21:13
2
2
What do you mean by "working just fine"? And does your assessment change if you do
x=1
followed by [[ x -gt 2]]
?– nohillside
Dec 3 '18 at 21:01
What do you mean by "working just fine"? And does your assessment change if you do
x=1
followed by [[ x -gt 2]]
?– nohillside
Dec 3 '18 at 21:01
I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)
– Guest
Dec 3 '18 at 21:13
I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)
– Guest
Dec 3 '18 at 21:13
add a comment |
3 Answers
3
active
oldest
votes
The reason is that the -eq
forces an arithmetic evaluation of the arguments.
An arithmetic operator: -eq
, -gt
, -lt
, -ge
, -le
and -ne
inside a [[ ]]
(in ksh,zsh and bash) means to automatically expand variable names as in the c language, not need for a leading $
.
For confirmation we must look into bash source code. The manual offers no direct confirmation.
Inside
test.c
the processing of arithmetic operators fall into this function:
arithcomp (s, t, op, flags)
Where
s
andt
are both operands. The operands are handed to this function:
l = evalexp (s, &expok);
r = evalexp (t, &expok);
The function
evalexp
is defined insideexpr.c
, which has this header:
/* expr.c -- arithmetic expression evaluation. */
So, yes, both sides of an arithmetic operator fall (directly) into arithmetic expression evaluation. Directly, no buts, no ifs.
In practice, with:
$ x=3
Both of this fail:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
Which is correct, x
is not being expanded and x
is not equal to a number.
However:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
The variable named x
gets expanded (even without a $).
This doesn't happen for a […]
in zsh or bash (it does in ksh).
That is the same as what happens inside a $((…))
:
$ echo $(( x + 7 ))
10
And, please understand that this is (very) recursive (except in dash and yash):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
A 😮
And quite risky:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
The syntax error could be easily avoided:
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
As the saying goes: sanitize your input
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
end of 😮
Both the (older) external /usr/bin/test
(not the builtin test
) and the still older and also external expr
do not expand expressions only integers (and apparently, only decimal integers):
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
Interesting. It's not hard to tell how this is possible - being[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus[[
can treat-eq
in a more smart way than, say,[
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations inman
orinfo bash
.
– fra-san
Dec 3 '18 at 23:55
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in thetest
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…
– Isaac
Dec 4 '18 at 1:03
add a comment |
The operands of the numerical comparisons -eq
, -gt
, -lt
, -ge
, -le
and -ne
are taken as arithmetic expressions. With some limitation, they still need to be single shell words.
The behaviour of variable names in arithmetic expression is described in Shell Arithmetic:
Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.
and also:
The value of a variable is evaluated as an arithmetic expression when it is referenced
But I can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. It's not described in Conditional Constructs under [[
, nor is it described in Bash Conditional Expressions.
But, by experiment, it seems to work as said above.
So, stuff like this works:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
this too (the value of the variable is evaluated):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
But this doesn't; it's not a single shell word when the [[ .. ]]
is parsed, so there's a syntax error in the conditional:
[[ 1 + 2 + 3 -eq 6 ]] && echo y
In other arithmetic contexts, there's no need for the expression to be without whitespace. This prints 999
, as the brackets unambiguously delimit the arithmetic expression in the index:
a[6]=999; echo ${a[1 + 2 + 3]}
On the other hand, the =
comparison is a pattern match, and doesn't involve arithmetic, nor the automatic variable expansion done in an arithmetic context (Conditional Constructs):
When the
==
and!=
operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. The=
operator is identical to==
.
So this is false since the strings are obviously different:
[[ "1 + 2 + 3" = 6 ]]
as is this, even though the numerical values are the same:
[[ 6 = 06 ]]
and here, too, the strings (x
and 6
) are compared, they're different:
x=6
[[ x = 6 ]]
This would expand the variable, though, so this is true:
x=6
[[ $x = 6 ]]
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
The closest thing is that the description ofarg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)
– Barmar
Dec 5 '18 at 17:20
@Barmar, ehh, right. But that applies to the numeric comparisons in[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.
– ilkkachu
Dec 5 '18 at 22:12
@ilkkachu[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.
– Barmar
Dec 5 '18 at 22:31
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to[
just as well as[[
. Even with[
, the operands to-eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to[
acting like an ordinary command, as you say.)
– ilkkachu
Dec 5 '18 at 22:55
|
show 1 more comment
Yes, your observation is correct, variable expansion is performed on expressions under double brackets [[ ]]
, so you don't need to put $
in front of a variable name.
This is explicitly stated in the bash
manual:
[[ expression ]]
(...) Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
Notice that this is not the case of single-bracket version [ ]
, as [
is not a shell keyword (syntax), but rather a command (in bash it is builtin, other shells could use external, lined to test).
1
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
3
It looks like there is more here:(x=1; [[ $x = 1 ]]; echo $?)
returns0
,(x=1; [[ x = 1 ]]; echo $?)
returns1
, i.e. parameter expansion is not performed onx
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in(x=1; echo $((x+1)))
. (About arithmetic evaluation,man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).
– fra-san
Dec 3 '18 at 21:47
@fra-san Indeed, because-gt
operator expects number so whole expression is re-evaluated as if inside(())
, on the other hand==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.
– jimmij
Dec 3 '18 at 22:04
[
is a shell builtin in bash.
– Nizam Mohamed
Dec 3 '18 at 22:41
1
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
|
show 2 more comments
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');
});
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%2f485766%2fautomatic-variable-expansion-inside-bash-command%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The reason is that the -eq
forces an arithmetic evaluation of the arguments.
An arithmetic operator: -eq
, -gt
, -lt
, -ge
, -le
and -ne
inside a [[ ]]
(in ksh,zsh and bash) means to automatically expand variable names as in the c language, not need for a leading $
.
For confirmation we must look into bash source code. The manual offers no direct confirmation.
Inside
test.c
the processing of arithmetic operators fall into this function:
arithcomp (s, t, op, flags)
Where
s
andt
are both operands. The operands are handed to this function:
l = evalexp (s, &expok);
r = evalexp (t, &expok);
The function
evalexp
is defined insideexpr.c
, which has this header:
/* expr.c -- arithmetic expression evaluation. */
So, yes, both sides of an arithmetic operator fall (directly) into arithmetic expression evaluation. Directly, no buts, no ifs.
In practice, with:
$ x=3
Both of this fail:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
Which is correct, x
is not being expanded and x
is not equal to a number.
However:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
The variable named x
gets expanded (even without a $).
This doesn't happen for a […]
in zsh or bash (it does in ksh).
That is the same as what happens inside a $((…))
:
$ echo $(( x + 7 ))
10
And, please understand that this is (very) recursive (except in dash and yash):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
A 😮
And quite risky:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
The syntax error could be easily avoided:
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
As the saying goes: sanitize your input
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
end of 😮
Both the (older) external /usr/bin/test
(not the builtin test
) and the still older and also external expr
do not expand expressions only integers (and apparently, only decimal integers):
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
Interesting. It's not hard to tell how this is possible - being[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus[[
can treat-eq
in a more smart way than, say,[
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations inman
orinfo bash
.
– fra-san
Dec 3 '18 at 23:55
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in thetest
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…
– Isaac
Dec 4 '18 at 1:03
add a comment |
The reason is that the -eq
forces an arithmetic evaluation of the arguments.
An arithmetic operator: -eq
, -gt
, -lt
, -ge
, -le
and -ne
inside a [[ ]]
(in ksh,zsh and bash) means to automatically expand variable names as in the c language, not need for a leading $
.
For confirmation we must look into bash source code. The manual offers no direct confirmation.
Inside
test.c
the processing of arithmetic operators fall into this function:
arithcomp (s, t, op, flags)
Where
s
andt
are both operands. The operands are handed to this function:
l = evalexp (s, &expok);
r = evalexp (t, &expok);
The function
evalexp
is defined insideexpr.c
, which has this header:
/* expr.c -- arithmetic expression evaluation. */
So, yes, both sides of an arithmetic operator fall (directly) into arithmetic expression evaluation. Directly, no buts, no ifs.
In practice, with:
$ x=3
Both of this fail:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
Which is correct, x
is not being expanded and x
is not equal to a number.
However:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
The variable named x
gets expanded (even without a $).
This doesn't happen for a […]
in zsh or bash (it does in ksh).
That is the same as what happens inside a $((…))
:
$ echo $(( x + 7 ))
10
And, please understand that this is (very) recursive (except in dash and yash):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
A 😮
And quite risky:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
The syntax error could be easily avoided:
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
As the saying goes: sanitize your input
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
end of 😮
Both the (older) external /usr/bin/test
(not the builtin test
) and the still older and also external expr
do not expand expressions only integers (and apparently, only decimal integers):
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
Interesting. It's not hard to tell how this is possible - being[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus[[
can treat-eq
in a more smart way than, say,[
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations inman
orinfo bash
.
– fra-san
Dec 3 '18 at 23:55
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in thetest
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…
– Isaac
Dec 4 '18 at 1:03
add a comment |
The reason is that the -eq
forces an arithmetic evaluation of the arguments.
An arithmetic operator: -eq
, -gt
, -lt
, -ge
, -le
and -ne
inside a [[ ]]
(in ksh,zsh and bash) means to automatically expand variable names as in the c language, not need for a leading $
.
For confirmation we must look into bash source code. The manual offers no direct confirmation.
Inside
test.c
the processing of arithmetic operators fall into this function:
arithcomp (s, t, op, flags)
Where
s
andt
are both operands. The operands are handed to this function:
l = evalexp (s, &expok);
r = evalexp (t, &expok);
The function
evalexp
is defined insideexpr.c
, which has this header:
/* expr.c -- arithmetic expression evaluation. */
So, yes, both sides of an arithmetic operator fall (directly) into arithmetic expression evaluation. Directly, no buts, no ifs.
In practice, with:
$ x=3
Both of this fail:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
Which is correct, x
is not being expanded and x
is not equal to a number.
However:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
The variable named x
gets expanded (even without a $).
This doesn't happen for a […]
in zsh or bash (it does in ksh).
That is the same as what happens inside a $((…))
:
$ echo $(( x + 7 ))
10
And, please understand that this is (very) recursive (except in dash and yash):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
A 😮
And quite risky:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
The syntax error could be easily avoided:
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
As the saying goes: sanitize your input
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
end of 😮
Both the (older) external /usr/bin/test
(not the builtin test
) and the still older and also external expr
do not expand expressions only integers (and apparently, only decimal integers):
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
The reason is that the -eq
forces an arithmetic evaluation of the arguments.
An arithmetic operator: -eq
, -gt
, -lt
, -ge
, -le
and -ne
inside a [[ ]]
(in ksh,zsh and bash) means to automatically expand variable names as in the c language, not need for a leading $
.
For confirmation we must look into bash source code. The manual offers no direct confirmation.
Inside
test.c
the processing of arithmetic operators fall into this function:
arithcomp (s, t, op, flags)
Where
s
andt
are both operands. The operands are handed to this function:
l = evalexp (s, &expok);
r = evalexp (t, &expok);
The function
evalexp
is defined insideexpr.c
, which has this header:
/* expr.c -- arithmetic expression evaluation. */
So, yes, both sides of an arithmetic operator fall (directly) into arithmetic expression evaluation. Directly, no buts, no ifs.
In practice, with:
$ x=3
Both of this fail:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
Which is correct, x
is not being expanded and x
is not equal to a number.
However:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
The variable named x
gets expanded (even without a $).
This doesn't happen for a […]
in zsh or bash (it does in ksh).
That is the same as what happens inside a $((…))
:
$ echo $(( x + 7 ))
10
And, please understand that this is (very) recursive (except in dash and yash):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
A 😮
And quite risky:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
The syntax error could be easily avoided:
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
As the saying goes: sanitize your input
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
end of 😮
Both the (older) external /usr/bin/test
(not the builtin test
) and the still older and also external expr
do not expand expressions only integers (and apparently, only decimal integers):
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
edited Dec 4 '18 at 9:20
answered Dec 3 '18 at 23:22
IsaacIsaac
11.6k11752
11.6k11752
Interesting. It's not hard to tell how this is possible - being[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus[[
can treat-eq
in a more smart way than, say,[
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations inman
orinfo bash
.
– fra-san
Dec 3 '18 at 23:55
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in thetest
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…
– Isaac
Dec 4 '18 at 1:03
add a comment |
Interesting. It's not hard to tell how this is possible - being[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus[[
can treat-eq
in a more smart way than, say,[
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations inman
orinfo bash
.
– fra-san
Dec 3 '18 at 23:55
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in thetest
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…
– Isaac
Dec 4 '18 at 1:03
Interesting. It's not hard to tell how this is possible - being
[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus [[
can treat -eq
in a more smart way than, say, [
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations in man
or info bash
.– fra-san
Dec 3 '18 at 23:55
Interesting. It's not hard to tell how this is possible - being
[[
a keyword, operators and operands are detected when the command is read and not after expansion. Thus [[
can treat -eq
in a more smart way than, say, [
. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations in man
or info bash
.– fra-san
Dec 3 '18 at 23:55
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the
test
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…– Isaac
Dec 4 '18 at 1:03
Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the
test
section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…– Isaac
Dec 4 '18 at 1:03
add a comment |
The operands of the numerical comparisons -eq
, -gt
, -lt
, -ge
, -le
and -ne
are taken as arithmetic expressions. With some limitation, they still need to be single shell words.
The behaviour of variable names in arithmetic expression is described in Shell Arithmetic:
Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.
and also:
The value of a variable is evaluated as an arithmetic expression when it is referenced
But I can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. It's not described in Conditional Constructs under [[
, nor is it described in Bash Conditional Expressions.
But, by experiment, it seems to work as said above.
So, stuff like this works:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
this too (the value of the variable is evaluated):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
But this doesn't; it's not a single shell word when the [[ .. ]]
is parsed, so there's a syntax error in the conditional:
[[ 1 + 2 + 3 -eq 6 ]] && echo y
In other arithmetic contexts, there's no need for the expression to be without whitespace. This prints 999
, as the brackets unambiguously delimit the arithmetic expression in the index:
a[6]=999; echo ${a[1 + 2 + 3]}
On the other hand, the =
comparison is a pattern match, and doesn't involve arithmetic, nor the automatic variable expansion done in an arithmetic context (Conditional Constructs):
When the
==
and!=
operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. The=
operator is identical to==
.
So this is false since the strings are obviously different:
[[ "1 + 2 + 3" = 6 ]]
as is this, even though the numerical values are the same:
[[ 6 = 06 ]]
and here, too, the strings (x
and 6
) are compared, they're different:
x=6
[[ x = 6 ]]
This would expand the variable, though, so this is true:
x=6
[[ $x = 6 ]]
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
The closest thing is that the description ofarg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)
– Barmar
Dec 5 '18 at 17:20
@Barmar, ehh, right. But that applies to the numeric comparisons in[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.
– ilkkachu
Dec 5 '18 at 22:12
@ilkkachu[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.
– Barmar
Dec 5 '18 at 22:31
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to[
just as well as[[
. Even with[
, the operands to-eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to[
acting like an ordinary command, as you say.)
– ilkkachu
Dec 5 '18 at 22:55
|
show 1 more comment
The operands of the numerical comparisons -eq
, -gt
, -lt
, -ge
, -le
and -ne
are taken as arithmetic expressions. With some limitation, they still need to be single shell words.
The behaviour of variable names in arithmetic expression is described in Shell Arithmetic:
Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.
and also:
The value of a variable is evaluated as an arithmetic expression when it is referenced
But I can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. It's not described in Conditional Constructs under [[
, nor is it described in Bash Conditional Expressions.
But, by experiment, it seems to work as said above.
So, stuff like this works:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
this too (the value of the variable is evaluated):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
But this doesn't; it's not a single shell word when the [[ .. ]]
is parsed, so there's a syntax error in the conditional:
[[ 1 + 2 + 3 -eq 6 ]] && echo y
In other arithmetic contexts, there's no need for the expression to be without whitespace. This prints 999
, as the brackets unambiguously delimit the arithmetic expression in the index:
a[6]=999; echo ${a[1 + 2 + 3]}
On the other hand, the =
comparison is a pattern match, and doesn't involve arithmetic, nor the automatic variable expansion done in an arithmetic context (Conditional Constructs):
When the
==
and!=
operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. The=
operator is identical to==
.
So this is false since the strings are obviously different:
[[ "1 + 2 + 3" = 6 ]]
as is this, even though the numerical values are the same:
[[ 6 = 06 ]]
and here, too, the strings (x
and 6
) are compared, they're different:
x=6
[[ x = 6 ]]
This would expand the variable, though, so this is true:
x=6
[[ $x = 6 ]]
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
The closest thing is that the description ofarg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)
– Barmar
Dec 5 '18 at 17:20
@Barmar, ehh, right. But that applies to the numeric comparisons in[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.
– ilkkachu
Dec 5 '18 at 22:12
@ilkkachu[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.
– Barmar
Dec 5 '18 at 22:31
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to[
just as well as[[
. Even with[
, the operands to-eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to[
acting like an ordinary command, as you say.)
– ilkkachu
Dec 5 '18 at 22:55
|
show 1 more comment
The operands of the numerical comparisons -eq
, -gt
, -lt
, -ge
, -le
and -ne
are taken as arithmetic expressions. With some limitation, they still need to be single shell words.
The behaviour of variable names in arithmetic expression is described in Shell Arithmetic:
Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.
and also:
The value of a variable is evaluated as an arithmetic expression when it is referenced
But I can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. It's not described in Conditional Constructs under [[
, nor is it described in Bash Conditional Expressions.
But, by experiment, it seems to work as said above.
So, stuff like this works:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
this too (the value of the variable is evaluated):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
But this doesn't; it's not a single shell word when the [[ .. ]]
is parsed, so there's a syntax error in the conditional:
[[ 1 + 2 + 3 -eq 6 ]] && echo y
In other arithmetic contexts, there's no need for the expression to be without whitespace. This prints 999
, as the brackets unambiguously delimit the arithmetic expression in the index:
a[6]=999; echo ${a[1 + 2 + 3]}
On the other hand, the =
comparison is a pattern match, and doesn't involve arithmetic, nor the automatic variable expansion done in an arithmetic context (Conditional Constructs):
When the
==
and!=
operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. The=
operator is identical to==
.
So this is false since the strings are obviously different:
[[ "1 + 2 + 3" = 6 ]]
as is this, even though the numerical values are the same:
[[ 6 = 06 ]]
and here, too, the strings (x
and 6
) are compared, they're different:
x=6
[[ x = 6 ]]
This would expand the variable, though, so this is true:
x=6
[[ $x = 6 ]]
The operands of the numerical comparisons -eq
, -gt
, -lt
, -ge
, -le
and -ne
are taken as arithmetic expressions. With some limitation, they still need to be single shell words.
The behaviour of variable names in arithmetic expression is described in Shell Arithmetic:
Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.
and also:
The value of a variable is evaluated as an arithmetic expression when it is referenced
But I can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. It's not described in Conditional Constructs under [[
, nor is it described in Bash Conditional Expressions.
But, by experiment, it seems to work as said above.
So, stuff like this works:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
this too (the value of the variable is evaluated):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
But this doesn't; it's not a single shell word when the [[ .. ]]
is parsed, so there's a syntax error in the conditional:
[[ 1 + 2 + 3 -eq 6 ]] && echo y
In other arithmetic contexts, there's no need for the expression to be without whitespace. This prints 999
, as the brackets unambiguously delimit the arithmetic expression in the index:
a[6]=999; echo ${a[1 + 2 + 3]}
On the other hand, the =
comparison is a pattern match, and doesn't involve arithmetic, nor the automatic variable expansion done in an arithmetic context (Conditional Constructs):
When the
==
and!=
operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. The=
operator is identical to==
.
So this is false since the strings are obviously different:
[[ "1 + 2 + 3" = 6 ]]
as is this, even though the numerical values are the same:
[[ 6 = 06 ]]
and here, too, the strings (x
and 6
) are compared, they're different:
x=6
[[ x = 6 ]]
This would expand the variable, though, so this is true:
x=6
[[ $x = 6 ]]
edited Dec 3 '18 at 23:57
answered Dec 3 '18 at 23:52
ilkkachuilkkachu
57k785158
57k785158
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
The closest thing is that the description ofarg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)
– Barmar
Dec 5 '18 at 17:20
@Barmar, ehh, right. But that applies to the numeric comparisons in[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.
– ilkkachu
Dec 5 '18 at 22:12
@ilkkachu[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.
– Barmar
Dec 5 '18 at 22:31
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to[
just as well as[[
. Even with[
, the operands to-eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to[
acting like an ordinary command, as you say.)
– ilkkachu
Dec 5 '18 at 22:55
|
show 1 more comment
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
The closest thing is that the description ofarg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)
– Barmar
Dec 5 '18 at 17:20
@Barmar, ehh, right. But that applies to the numeric comparisons in[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.
– ilkkachu
Dec 5 '18 at 22:12
@ilkkachu[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.
– Barmar
Dec 5 '18 at 22:31
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to[
just as well as[[
. Even with[
, the operands to-eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to[
acting like an ordinary command, as you say.)
– ilkkachu
Dec 5 '18 at 22:55
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.
– Isaac
Dec 4 '18 at 1:09
The closest thing is that the description of
arg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)– Barmar
Dec 5 '18 at 17:20
The closest thing is that the description of
arg1 OP arg2
says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)– Barmar
Dec 5 '18 at 17:20
@Barmar, ehh, right. But that applies to the numeric comparisons in
[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.– ilkkachu
Dec 5 '18 at 22:12
@Barmar, ehh, right. But that applies to the numeric comparisons in
[
too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.– ilkkachu
Dec 5 '18 at 22:12
@ilkkachu
[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.– Barmar
Dec 5 '18 at 22:31
@ilkkachu
[
is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.– Barmar
Dec 5 '18 at 22:31
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to
[
just as well as [[
. Even with [
, the operands to -eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [
acting like an ordinary command, as you say.)– ilkkachu
Dec 5 '18 at 22:55
@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to
[
just as well as [[
. Even with [
, the operands to -eq
and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [
acting like an ordinary command, as you say.)– ilkkachu
Dec 5 '18 at 22:55
|
show 1 more comment
Yes, your observation is correct, variable expansion is performed on expressions under double brackets [[ ]]
, so you don't need to put $
in front of a variable name.
This is explicitly stated in the bash
manual:
[[ expression ]]
(...) Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
Notice that this is not the case of single-bracket version [ ]
, as [
is not a shell keyword (syntax), but rather a command (in bash it is builtin, other shells could use external, lined to test).
1
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
3
It looks like there is more here:(x=1; [[ $x = 1 ]]; echo $?)
returns0
,(x=1; [[ x = 1 ]]; echo $?)
returns1
, i.e. parameter expansion is not performed onx
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in(x=1; echo $((x+1)))
. (About arithmetic evaluation,man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).
– fra-san
Dec 3 '18 at 21:47
@fra-san Indeed, because-gt
operator expects number so whole expression is re-evaluated as if inside(())
, on the other hand==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.
– jimmij
Dec 3 '18 at 22:04
[
is a shell builtin in bash.
– Nizam Mohamed
Dec 3 '18 at 22:41
1
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
|
show 2 more comments
Yes, your observation is correct, variable expansion is performed on expressions under double brackets [[ ]]
, so you don't need to put $
in front of a variable name.
This is explicitly stated in the bash
manual:
[[ expression ]]
(...) Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
Notice that this is not the case of single-bracket version [ ]
, as [
is not a shell keyword (syntax), but rather a command (in bash it is builtin, other shells could use external, lined to test).
1
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
3
It looks like there is more here:(x=1; [[ $x = 1 ]]; echo $?)
returns0
,(x=1; [[ x = 1 ]]; echo $?)
returns1
, i.e. parameter expansion is not performed onx
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in(x=1; echo $((x+1)))
. (About arithmetic evaluation,man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).
– fra-san
Dec 3 '18 at 21:47
@fra-san Indeed, because-gt
operator expects number so whole expression is re-evaluated as if inside(())
, on the other hand==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.
– jimmij
Dec 3 '18 at 22:04
[
is a shell builtin in bash.
– Nizam Mohamed
Dec 3 '18 at 22:41
1
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
|
show 2 more comments
Yes, your observation is correct, variable expansion is performed on expressions under double brackets [[ ]]
, so you don't need to put $
in front of a variable name.
This is explicitly stated in the bash
manual:
[[ expression ]]
(...) Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
Notice that this is not the case of single-bracket version [ ]
, as [
is not a shell keyword (syntax), but rather a command (in bash it is builtin, other shells could use external, lined to test).
Yes, your observation is correct, variable expansion is performed on expressions under double brackets [[ ]]
, so you don't need to put $
in front of a variable name.
This is explicitly stated in the bash
manual:
[[ expression ]]
(...) Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
Notice that this is not the case of single-bracket version [ ]
, as [
is not a shell keyword (syntax), but rather a command (in bash it is builtin, other shells could use external, lined to test).
edited Dec 3 '18 at 23:04
answered Dec 3 '18 at 21:22
jimmijjimmij
31.1k871106
31.1k871106
1
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
3
It looks like there is more here:(x=1; [[ $x = 1 ]]; echo $?)
returns0
,(x=1; [[ x = 1 ]]; echo $?)
returns1
, i.e. parameter expansion is not performed onx
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in(x=1; echo $((x+1)))
. (About arithmetic evaluation,man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).
– fra-san
Dec 3 '18 at 21:47
@fra-san Indeed, because-gt
operator expects number so whole expression is re-evaluated as if inside(())
, on the other hand==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.
– jimmij
Dec 3 '18 at 22:04
[
is a shell builtin in bash.
– Nizam Mohamed
Dec 3 '18 at 22:41
1
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
|
show 2 more comments
1
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
3
It looks like there is more here:(x=1; [[ $x = 1 ]]; echo $?)
returns0
,(x=1; [[ x = 1 ]]; echo $?)
returns1
, i.e. parameter expansion is not performed onx
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in(x=1; echo $((x+1)))
. (About arithmetic evaluation,man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).
– fra-san
Dec 3 '18 at 21:47
@fra-san Indeed, because-gt
operator expects number so whole expression is re-evaluated as if inside(())
, on the other hand==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.
– jimmij
Dec 3 '18 at 22:04
[
is a shell builtin in bash.
– Nizam Mohamed
Dec 3 '18 at 22:41
1
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
1
1
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.
– Guest
Dec 3 '18 at 21:35
3
3
It looks like there is more here:
(x=1; [[ $x = 1 ]]; echo $?)
returns 0
, (x=1; [[ x = 1 ]]; echo $?)
returns 1
, i.e. parameter expansion is not performed on x
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1)))
. (About arithmetic evaluation, man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).– fra-san
Dec 3 '18 at 21:47
It looks like there is more here:
(x=1; [[ $x = 1 ]]; echo $?)
returns 0
, (x=1; [[ x = 1 ]]; echo $?)
returns 1
, i.e. parameter expansion is not performed on x
when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1)))
. (About arithmetic evaluation, man bash
states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).– fra-san
Dec 3 '18 at 21:47
@fra-san Indeed, because
-gt
operator expects number so whole expression is re-evaluated as if inside (())
, on the other hand ==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.– jimmij
Dec 3 '18 at 22:04
@fra-san Indeed, because
-gt
operator expects number so whole expression is re-evaluated as if inside (())
, on the other hand ==
expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.– jimmij
Dec 3 '18 at 22:04
[
is a shell builtin in bash.– Nizam Mohamed
Dec 3 '18 at 22:41
[
is a shell builtin in bash.– Nizam Mohamed
Dec 3 '18 at 22:41
1
1
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
Dec 3 '18 at 23:08
|
show 2 more comments
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');
});
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%2f485766%2fautomatic-variable-expansion-inside-bash-command%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');
});
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');
});
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');
});
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
2
What do you mean by "working just fine"? And does your assessment change if you do
x=1
followed by[[ x -gt 2]]
?– nohillside
Dec 3 '18 at 21:01
I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)
– Guest
Dec 3 '18 at 21:13