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)










share|improve this question









New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 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
    5 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
    5 hours ago















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)










share|improve this question









New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 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
    5 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
    5 hours ago













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)










share|improve this question









New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











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






share|improve this question









New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 1 hour ago









Isaac

10.2k11445




10.2k11445






New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 6 hours ago









Guest

392




392




New contributor




Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Guest is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 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
    5 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
    5 hours ago














  • 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
    5 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
    5 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
5 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
5 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
5 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
5 hours ago










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 and t are both operands. The operands are handed to this function:



    l = evalexp (s, &expok);
    r = evalexp (t, &expok);


    The function evalexp is defined inside expr.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





share|improve this answer























  • 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
    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
    1 hour ago


















up vote
1
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).






share|improve this answer



















  • 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
    5 hours ago








  • 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
    5 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
    4 hours ago










  • [ is a shell builtin in bash.
    – Nizam Mohamed
    4 hours ago










  • @NizamMohamed It is a builtin, but it's still not a keyword.
    – Kusalananda
    3 hours ago


















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 ]]





share|improve this answer























  • 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
    1 hour ago











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',
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
});


}
});






Guest is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















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








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 and t are both operands. The operands are handed to this function:



    l = evalexp (s, &expok);
    r = evalexp (t, &expok);


    The function evalexp is defined inside expr.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





share|improve this answer























  • 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
    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
    1 hour ago















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 and t are both operands. The operands are handed to this function:



    l = evalexp (s, &expok);
    r = evalexp (t, &expok);


    The function evalexp is defined inside expr.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





share|improve this answer























  • 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
    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
    1 hour ago













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 and t are both operands. The operands are handed to this function:



    l = evalexp (s, &expok);
    r = evalexp (t, &expok);


    The function evalexp is defined inside expr.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





share|improve this answer














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 and t are both operands. The operands are handed to this function:



    l = evalexp (s, &expok);
    r = evalexp (t, &expok);


    The function evalexp is defined inside expr.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






share|improve this answer














share|improve this answer



share|improve this answer








edited 35 mins ago

























answered 3 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 in man or info bash.
    – fra-san
    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
    1 hour 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
    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
    1 hour 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
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
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
1 hour 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
1 hour ago












up vote
1
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).






share|improve this answer



















  • 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
    5 hours ago








  • 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
    5 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
    4 hours ago










  • [ is a shell builtin in bash.
    – Nizam Mohamed
    4 hours ago










  • @NizamMohamed It is a builtin, but it's still not a keyword.
    – Kusalananda
    3 hours ago















up vote
1
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).






share|improve this answer



















  • 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
    5 hours ago








  • 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
    5 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
    4 hours ago










  • [ is a shell builtin in bash.
    – Nizam Mohamed
    4 hours ago










  • @NizamMohamed It is a builtin, but it's still not a keyword.
    – Kusalananda
    3 hours ago













up vote
1
down vote










up vote
1
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).






share|improve this answer














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).







share|improve this answer














share|improve this answer



share|improve this answer








edited 3 hours ago

























answered 5 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
    5 hours ago








  • 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
    5 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
    4 hours ago










  • [ is a shell builtin in bash.
    – Nizam Mohamed
    4 hours ago










  • @NizamMohamed It is a builtin, but it's still not a keyword.
    – Kusalananda
    3 hours ago














  • 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
    5 hours ago








  • 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
    5 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
    4 hours ago










  • [ is a shell builtin in bash.
    – Nizam Mohamed
    4 hours ago










  • @NizamMohamed It is a builtin, but it's still not a keyword.
    – Kusalananda
    3 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
5 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
5 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
5 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
5 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
4 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
4 hours ago












[ is a shell builtin in bash.
– Nizam Mohamed
4 hours ago




[ is a shell builtin in bash.
– Nizam Mohamed
4 hours ago












@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
3 hours ago




@NizamMohamed It is a builtin, but it's still not a keyword.
– Kusalananda
3 hours ago










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 ]]





share|improve this answer























  • 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
    1 hour ago















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 ]]





share|improve this answer























  • 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
    1 hour ago













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 ]]





share|improve this answer














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 ]]






share|improve this answer














share|improve this answer



share|improve this answer








edited 2 hours ago

























answered 3 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
    1 hour 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
    1 hour 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
1 hour 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
1 hour ago










Guest is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

數位音樂下載

When can things happen in Etherscan, such as the picture below?

格利澤436b