Automatic variable expansion inside bash [[ ]] command












11















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




















  • 2





    What do you mean by "working just fine"? And does your assessment change if you do x=1 followed by [[ x -gt 2]]?

    – nohillside
    Dec 3 '18 at 21:01











  • I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)

    – Guest
    Dec 3 '18 at 21:13
















11















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




















  • 2





    What do you mean by "working just fine"? And does your assessment change if you do x=1 followed by [[ x -gt 2]]?

    – nohillside
    Dec 3 '18 at 21:01











  • I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)

    – Guest
    Dec 3 '18 at 21:13














11












11








11


1






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
















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















share|improve this question













share|improve this question




share|improve this question








edited Dec 4 '18 at 1:11









Isaac

11.8k11752




11.8k11752










asked Dec 3 '18 at 20:47









GuestGuest

593




593








  • 2





    What do you mean by "working just fine"? And does your assessment change if you do x=1 followed by [[ x -gt 2]]?

    – nohillside
    Dec 3 '18 at 21:01











  • I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)

    – Guest
    Dec 3 '18 at 21:13














  • 2





    What do you mean by "working just fine"? And does your assessment change if you do x=1 followed by [[ x -gt 2]]?

    – nohillside
    Dec 3 '18 at 21:01











  • I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)

    – Guest
    Dec 3 '18 at 21:13








2




2





What do you mean by "working just fine"? And does your assessment change if you do x=1 followed by [[ x -gt 2]]?

– nohillside
Dec 3 '18 at 21:01





What do you mean by "working just fine"? And does your assessment change if you do x=1 followed by [[ x -gt 2]]?

– nohillside
Dec 3 '18 at 21:01













I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)

– Guest
Dec 3 '18 at 21:13





I mean: How and why the [[ ]] command is dereferencing my variable x without the $ sign. And yes, if x=1, the statement is false (return status 1)

– Guest
Dec 3 '18 at 21:13










3 Answers
3






active

oldest

votes


















9














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


A 😮



And quite risky:



 $ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")


The syntax error could be easily avoided:



 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes


As the saying goes: sanitize your input



 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no


end of 😮





Both the (older) external /usr/bin/test (not the builtin test) and the still older and also external expr do not expand expressions only integers (and apparently, only decimal integers):



 $ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’

$ expr x + 3
expr: non-integer argument





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
    Dec 3 '18 at 23:55













  • Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

    – Isaac
    Dec 4 '18 at 1:03



















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





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
    Dec 4 '18 at 1:09











  • The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

    – Barmar
    Dec 5 '18 at 17:20











  • @Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

    – ilkkachu
    Dec 5 '18 at 22:12











  • @ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

    – Barmar
    Dec 5 '18 at 22:31











  • @Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

    – ilkkachu
    Dec 5 '18 at 22:55



















1














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
    Dec 3 '18 at 21:35








  • 3





    It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

    – fra-san
    Dec 3 '18 at 21:47











  • @fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

    – jimmij
    Dec 3 '18 at 22:04











  • [ is a shell builtin in bash.

    – Nizam Mohamed
    Dec 3 '18 at 22:41






  • 1





    @NizamMohamed It is a builtin, but it's still not a keyword.

    – Kusalananda
    Dec 3 '18 at 23:08











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














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









9














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


A 😮



And quite risky:



 $ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")


The syntax error could be easily avoided:



 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes


As the saying goes: sanitize your input



 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no


end of 😮





Both the (older) external /usr/bin/test (not the builtin test) and the still older and also external expr do not expand expressions only integers (and apparently, only decimal integers):



 $ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’

$ expr x + 3
expr: non-integer argument





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
    Dec 3 '18 at 23:55













  • Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

    – Isaac
    Dec 4 '18 at 1:03
















9














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


A 😮



And quite risky:



 $ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")


The syntax error could be easily avoided:



 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes


As the saying goes: sanitize your input



 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no


end of 😮





Both the (older) external /usr/bin/test (not the builtin test) and the still older and also external expr do not expand expressions only integers (and apparently, only decimal integers):



 $ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’

$ expr x + 3
expr: non-integer argument





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
    Dec 3 '18 at 23:55













  • Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

    – Isaac
    Dec 4 '18 at 1:03














9












9








9







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


A 😮



And quite risky:



 $ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")


The syntax error could be easily avoided:



 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes


As the saying goes: sanitize your input



 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no


end of 😮





Both the (older) external /usr/bin/test (not the builtin test) and the still older and also external expr do not expand expressions only integers (and apparently, only decimal integers):



 $ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’

$ expr x + 3
expr: non-integer argument





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


A 😮



And quite risky:



 $ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")


The syntax error could be easily avoided:



 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes


As the saying goes: sanitize your input



 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no


end of 😮





Both the (older) external /usr/bin/test (not the builtin test) and the still older and also external expr do not expand expressions only integers (and apparently, only decimal integers):



 $ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’

$ expr x + 3
expr: non-integer argument






share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 4 '18 at 9:20

























answered Dec 3 '18 at 23:22









IsaacIsaac

11.8k11752




11.8k11752













  • Interesting. It's not hard to tell how this is possible - being [[ a keyword, operators and operands are detected when the command is read and not after expansion. Thus [[ can treat -eq in a more smart way than, say, [. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations in man or info bash.

    – fra-san
    Dec 3 '18 at 23:55













  • Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

    – Isaac
    Dec 4 '18 at 1:03



















  • Interesting. It's not hard to tell how this is possible - being [[ a keyword, operators and operands are detected when the command is read and not after expansion. Thus [[ can treat -eq in a more smart way than, say, [. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations in man or info bash.

    – fra-san
    Dec 3 '18 at 23:55













  • Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

    – Isaac
    Dec 4 '18 at 1:03

















Interesting. It's not hard to tell how this is possible - being [[ a keyword, operators and operands are detected when the command is read and not after expansion. Thus [[ can treat -eq in a more smart way than, say, [. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations in man or info bash.

– fra-san
Dec 3 '18 at 23:55







Interesting. It's not hard to tell how this is possible - being [[ a keyword, operators and operands are detected when the command is read and not after expansion. Thus [[ can treat -eq in a more smart way than, say, [. But what I wonder is: where can we find documentation about the logic bash uses to interpret compound commands? It doesn't look quite obvious to me and I'm apparently unable to find satisfactory explanations in man or info bash.

– fra-san
Dec 3 '18 at 23:55















Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

– Isaac
Dec 4 '18 at 1:03





Bash doesn't document this anywhere I can find. There is a kind of description in man ksh93: The following obsolete arithmetic comparisons are also permitted: exp1 -eq exp2. There is this text in the test section of man zshbuiltins arithmetic operators expect integer arguments rather than arithmetic expressions. Which confirms that some arguments are treated as arithmetic expressions by the test builtin under conditions non specified in this quote. I'll confirm with the source code ….…

– Isaac
Dec 4 '18 at 1:03













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





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
    Dec 4 '18 at 1:09











  • The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

    – Barmar
    Dec 5 '18 at 17:20











  • @Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

    – ilkkachu
    Dec 5 '18 at 22:12











  • @ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

    – Barmar
    Dec 5 '18 at 22:31











  • @Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

    – ilkkachu
    Dec 5 '18 at 22:55
















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





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
    Dec 4 '18 at 1:09











  • The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

    – Barmar
    Dec 5 '18 at 17:20











  • @Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

    – ilkkachu
    Dec 5 '18 at 22:12











  • @ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

    – Barmar
    Dec 5 '18 at 22:31











  • @Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

    – ilkkachu
    Dec 5 '18 at 22:55














6












6








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





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 Dec 3 '18 at 23:57

























answered Dec 3 '18 at 23:52









ilkkachuilkkachu

57.3k786159




57.3k786159













  • can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.

    – Isaac
    Dec 4 '18 at 1:09











  • The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

    – Barmar
    Dec 5 '18 at 17:20











  • @Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

    – ilkkachu
    Dec 5 '18 at 22:12











  • @ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

    – Barmar
    Dec 5 '18 at 22:31











  • @Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

    – ilkkachu
    Dec 5 '18 at 22:55



















  • can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.

    – Isaac
    Dec 4 '18 at 1:09











  • The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

    – Barmar
    Dec 5 '18 at 17:20











  • @Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

    – ilkkachu
    Dec 5 '18 at 22:12











  • @ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

    – Barmar
    Dec 5 '18 at 22:31











  • @Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

    – ilkkachu
    Dec 5 '18 at 22:55

















can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.

– Isaac
Dec 4 '18 at 1:09





can't actually find the part of the documentation where it's said that the numeric comparisons take arithmetic expressions. The confirmation is in the code.

– Isaac
Dec 4 '18 at 1:09













The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

– Barmar
Dec 5 '18 at 17:20





The closest thing is that the description of arg1 OP arg2 says that the args may be positive or negative integers, which I guess is supposed to imply that they're treated as arithmetic expressions. Confusingly, it also implies that they can't be zero. :)

– Barmar
Dec 5 '18 at 17:20













@Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

– ilkkachu
Dec 5 '18 at 22:12





@Barmar, ehh, right. But that applies to the numeric comparisons in [ too, and there they aren't arithmetic expressions. Instead, Bash complains about non-integers.

– ilkkachu
Dec 5 '18 at 22:12













@ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

– Barmar
Dec 5 '18 at 22:31





@ilkkachu [ is an external command, it doesn't have access to shell variables. It's often optimized with a built-in command, but it still behaves the same.

– Barmar
Dec 5 '18 at 22:31













@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

– ilkkachu
Dec 5 '18 at 22:55





@Barmar, what I meant was that the phrase "Arg1 and arg2 may be positive or negative integers." appears in Bash Conditional Expressions, and that list applies to [ just as well as [[. Even with [, the operands to -eq and friends are/have to be integers, so that description also applies. Taking "must be integers" to mean "are interpreted as arithmetic expressions" doesn't apply in both cases. (Probably at least partly due to [ acting like an ordinary command, as you say.)

– ilkkachu
Dec 5 '18 at 22:55











1














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
    Dec 3 '18 at 21:35








  • 3





    It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

    – fra-san
    Dec 3 '18 at 21:47











  • @fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

    – jimmij
    Dec 3 '18 at 22:04











  • [ is a shell builtin in bash.

    – Nizam Mohamed
    Dec 3 '18 at 22:41






  • 1





    @NizamMohamed It is a builtin, but it's still not a keyword.

    – Kusalananda
    Dec 3 '18 at 23:08
















1














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
    Dec 3 '18 at 21:35








  • 3





    It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

    – fra-san
    Dec 3 '18 at 21:47











  • @fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

    – jimmij
    Dec 3 '18 at 22:04











  • [ is a shell builtin in bash.

    – Nizam Mohamed
    Dec 3 '18 at 22:41






  • 1





    @NizamMohamed It is a builtin, but it's still not a keyword.

    – Kusalananda
    Dec 3 '18 at 23:08














1












1








1







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 Dec 3 '18 at 23:04

























answered Dec 3 '18 at 21:22









jimmijjimmij

31.2k871106




31.2k871106








  • 1





    Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.

    – Guest
    Dec 3 '18 at 21:35








  • 3





    It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

    – fra-san
    Dec 3 '18 at 21:47











  • @fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

    – jimmij
    Dec 3 '18 at 22:04











  • [ is a shell builtin in bash.

    – Nizam Mohamed
    Dec 3 '18 at 22:41






  • 1





    @NizamMohamed It is a builtin, but it's still not a keyword.

    – Kusalananda
    Dec 3 '18 at 23:08














  • 1





    Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.

    – Guest
    Dec 3 '18 at 21:35








  • 3





    It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

    – fra-san
    Dec 3 '18 at 21:47











  • @fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

    – jimmij
    Dec 3 '18 at 22:04











  • [ is a shell builtin in bash.

    – Nizam Mohamed
    Dec 3 '18 at 22:41






  • 1





    @NizamMohamed It is a builtin, but it's still not a keyword.

    – Kusalananda
    Dec 3 '18 at 23:08








1




1





Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.

– Guest
Dec 3 '18 at 21:35







Thank you for replying. It seems that this is working only for numbers. x=city [[ $x == city ]] This doesn't work without the $ sign.

– Guest
Dec 3 '18 at 21:35






3




3





It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

– fra-san
Dec 3 '18 at 21:47





It looks like there is more here: (x=1; [[ $x = 1 ]]; echo $?) returns 0, (x=1; [[ x = 1 ]]; echo $?) returns 1, i.e. parameter expansion is not performed on x when we compare strings. This behavior looks like arithmetic evaluation triggered by arithmetic expansion, i.e. what happens in (x=1; echo $((x+1))). (About arithmetic evaluation, man bash states that "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax).

– fra-san
Dec 3 '18 at 21:47













@fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

– jimmij
Dec 3 '18 at 22:04





@fra-san Indeed, because -gt operator expects number so whole expression is re-evaluated as if inside (()), on the other hand == expects strings so instead pattern-matching function is triggered. I didn't dig into source code, but sounds reasonable.

– jimmij
Dec 3 '18 at 22:04













[ is a shell builtin in bash.

– Nizam Mohamed
Dec 3 '18 at 22:41





[ is a shell builtin in bash.

– Nizam Mohamed
Dec 3 '18 at 22:41




1




1





@NizamMohamed It is a builtin, but it's still not a keyword.

– Kusalananda
Dec 3 '18 at 23:08





@NizamMohamed It is a builtin, but it's still not a keyword.

– Kusalananda
Dec 3 '18 at 23:08


















draft saved

draft discarded




















































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.




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

Plaza Victoria

In PowerPoint, is there a keyboard shortcut for bulleted / numbered list?

How to put 3 figures in Latex with 2 figures side by side and 1 below these side by side images but in...