Automatic variable expansion inside bash [[ ]] command
up vote
7
down vote
favorite
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
New contributor
add a comment |
up vote
7
down vote
favorite
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
New contributor
2
What do you mean by "working just fine"? And does your assessment change if you dox=1
followed by[[ x -gt 2]]
?
– nohillside
7 hours ago
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
7 hours ago
add a comment |
up vote
7
down vote
favorite
up vote
7
down vote
favorite
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
New contributor
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
New contributor
New contributor
edited 3 hours ago
Isaac
10.2k11445
10.2k11445
New contributor
asked 7 hours ago
Guest
392
392
New contributor
New contributor
2
What do you mean by "working just fine"? And does your assessment change if you dox=1
followed by[[ x -gt 2]]
?
– nohillside
7 hours ago
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
7 hours ago
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
7 hours ago
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
7 hours ago
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
7 hours ago
What do you mean by "working just fine"? And does your assessment change if you do
x=1
followed by [[ x -gt 2]]
?– nohillside
7 hours ago
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
7 hours ago
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
7 hours ago
add a comment |
3 Answers
3
active
oldest
votes
up vote
2
down vote
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
😮
And quite risky:
$ x=$(date)
$ [[ x -eq 3 ]] && echo yes || echo no
bash: [[: Mon Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
no
The syntax error could be easily avoided:
$ x=$(date >/dev/null; echo 3)
$ [[ x -eq 3 ]] && echo yes || echo no
yes
😮
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
4 hours ago
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
3 hours ago
add a comment |
up vote
1
down vote
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
3 hours ago
add a comment |
up vote
0
down vote
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
7 hours ago
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
6 hours ago
@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
6 hours ago
[
is a shell builtin in bash.
– Nizam Mohamed
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
|
show 2 more comments
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
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
😮
And quite risky:
$ x=$(date)
$ [[ x -eq 3 ]] && echo yes || echo no
bash: [[: Mon Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
no
The syntax error could be easily avoided:
$ x=$(date >/dev/null; echo 3)
$ [[ x -eq 3 ]] && echo yes || echo no
yes
😮
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
4 hours ago
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
3 hours ago
add a comment |
up vote
2
down vote
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
😮
And quite risky:
$ x=$(date)
$ [[ x -eq 3 ]] && echo yes || echo no
bash: [[: Mon Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
no
The syntax error could be easily avoided:
$ x=$(date >/dev/null; echo 3)
$ [[ x -eq 3 ]] && echo yes || echo no
yes
😮
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
4 hours ago
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
3 hours ago
add a comment |
up vote
2
down vote
up vote
2
down vote
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
😮
And quite risky:
$ x=$(date)
$ [[ x -eq 3 ]] && echo yes || echo no
bash: [[: Mon Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
no
The syntax error could be easily avoided:
$ x=$(date >/dev/null; echo 3)
$ [[ x -eq 3 ]] && echo yes || echo no
yes
😮
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
😮
And quite risky:
$ x=$(date)
$ [[ x -eq 3 ]] && echo yes || echo no
bash: [[: Mon Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
no
The syntax error could be easily avoided:
$ x=$(date >/dev/null; echo 3)
$ [[ x -eq 3 ]] && echo yes || echo no
yes
😮
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 2 hours ago
answered 5 hours ago
Isaac
10.2k11445
10.2k11445
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
4 hours ago
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
3 hours ago
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
4 hours ago
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
3 hours ago
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
4 hours ago
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
4 hours ago
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
3 hours ago
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
3 hours ago
add a comment |
up vote
1
down vote
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
3 hours ago
add a comment |
up vote
1
down vote
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
3 hours ago
add a comment |
up vote
1
down vote
up vote
1
down vote
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 4 hours ago
answered 4 hours ago
ilkkachu
54.2k782147
54.2k782147
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
3 hours ago
add a 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
3 hours ago
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
3 hours ago
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
3 hours ago
add a comment |
up vote
0
down vote
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
7 hours ago
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
6 hours ago
@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
6 hours ago
[
is a shell builtin in bash.
– Nizam Mohamed
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
|
show 2 more comments
up vote
0
down vote
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
7 hours ago
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
6 hours ago
@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
6 hours ago
[
is a shell builtin in bash.
– Nizam Mohamed
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
|
show 2 more comments
up vote
0
down vote
up vote
0
down vote
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 5 hours ago
answered 7 hours ago
jimmij
30.4k869103
30.4k869103
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
7 hours ago
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
6 hours ago
@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
6 hours ago
[
is a shell builtin in bash.
– Nizam Mohamed
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
|
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
7 hours ago
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
6 hours ago
@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
6 hours ago
[
is a shell builtin in bash.
– Nizam Mohamed
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
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
7 hours ago
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
7 hours ago
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
6 hours ago
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
6 hours ago
@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
6 hours ago
@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
6 hours ago
[
is a shell builtin in bash.– Nizam Mohamed
5 hours ago
[
is a shell builtin in bash.– Nizam Mohamed
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
5 hours ago
|
show 2 more comments
Guest is a new contributor. Be nice, and check out our Code of Conduct.
Guest is a new contributor. Be nice, and check out our Code of Conduct.
Guest is a new contributor. Be nice, and check out our Code of Conduct.
Guest is a new contributor. Be nice, and check out our Code of Conduct.
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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
7 hours ago
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
7 hours ago