LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   question about command substitution and if statements (https://www.linuxquestions.org/questions/linux-newbie-8/question-about-command-substitution-and-if-statements-4175456525/)

mrb3nnio 04-02-2013 09:32 AM

question about command substitution and if statements
 
Hi guys,
I've been reading various websites about bash, and I still can't figure out why this simple command is causing errors.

I know it's something to do with incorrect expansion, but I can't see what the problem is:

so basically I have an "if" statement in a script;

if [ $( expr ${NPROC} % 16) -eq 0 ]
then
....

and this is giving an error:
[12: command not found

where 12 is the correct value of `expr ${NPROC} % 16`

Now I've spent a while fannying around with trying quotes in various combinations (both around the comparison target and the command), and trying different expansions like arithmetic etc and it still isn't working. I realise it should be easy.

Any help regarding figuring out the correct way to do the command substitution would be very welcome, I'd rather learn how to fix this broken expression than an alternative method.

Hope to hear back, cheers guys and girls

mrb3nnio

Edit:

ok wow, I didn't realise if conditions needed a space at either side of the content (i.e. [ condition ])
I didn't have that in before, seems I needed it.
Thanks anyway
Feel free to delete this post Mod

millgates 04-02-2013 09:50 AM

Make sure there's a space between the brackets and whatever is inside them. The [ bracket is not really an operator, but an actual command (usually /usr/bin/[ or a shell builtin, a synonym to test, so it needs to be separated from other tokens by spaces so that the command may be parsed by bash correctly. The closing ] bracket is actually an argument to [, for the sake of intuitivity and readability of the code.

So,

Code:

if [ 12 -eq 16 ]
is correct,
Code:

if [12 -eq 16]
is not.

That said, instead of expr and [ ], I would recommend to use the bash feature [[ ]], which actually is an operator, and in the case of arithmetical expressions, such as this, the (( )) construct. So,

Code:

if (( NPROC % 16 == 0 )); then ...
or

Code:

((NPROC % 16 == 0)) && ...
or even

Code:

((NPROC % 16)) || ...

mrb3nnio 04-02-2013 09:57 AM

That's interesting about "[" being a command, thanks for the help buddy!

David the H. 04-02-2013 11:35 AM

Please use ***[code][/code]*** tags around your code and data, to preserve the original formatting and to improve readability. Do not use quote tags, bolding, colors, "start/end" lines, or other creative techniques.


Another aspect of "[" being a command is that it's very strict about the number and type of arguments that follow it. A two-value comparison must have exactly four arguments following it, valueA, comparator, valueB, end-bracket. If you're using a variable or something that expands into more values than that, or less, you're going to have trouble:

Bash Pitfall #4, among others.

So remember to always quote your arguments.


That's why, as millgates said, when using advanced shells like bash or ksh it's recommended to use [[..]] for string/file tests, and ((..)) for numerical tests. Avoid using the old [..] test unless you specifically need POSIX-style portability.

Being built-in keywords, rather than separate commands, they can parse their arguments more intelligently, and so have fewer limitations than the old test.

http://mywiki.wooledge.org/BashFAQ/031
http://mywiki.wooledge.org/ArithmeticExpression


Now for one more thing. As the BashGuide says, "expr is a relic of ancient Rome. Do not wield it.". :) There is nothing that expr does that cannot be more efficiently done with modern shell built-ins. Unless you're using a truly ancient shell, put it away and forget about it.

In fact, AFAICT, there's only thing expr does that bash can't do directly, and that's return the index number of a character in a string. But even that can be worked around very easily with a couple of simple parameter substitutions.
Code:

$ string=foobarbazbumfoobarbazbum
$ expr index "$string" b
4
$ n="${string%%b*}_" ; echo "${#n}"
4

In fact, it's even more flexible, because you can also get the index of the last occurrence the same way, as well as other things like the beginning of longer strings:

Code:

$ n="${string%b*}_" ; echo "${#n}"
22
$ n="${string%%baz*}_" ; echo "${#n}"
7
$ n="${string%baz*}_" ; echo "${#n}"
19



All times are GMT -5. The time now is 10:19 AM.