LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   'for' loop in bash script (http://www.linuxquestions.org/questions/programming-9/%27for%27-loop-in-bash-script-944712/)

vjramana 05-13-2012 06:39 AM

'for' loop in bash script
 
Dear experts,

I am writing a bash script. At some point of the program I need to have 'for' loop. For simplicity I tried with some other simple code. The format of the loop is given below.

Code:

k=51
m=55

for j in {$k..$m};do
        w=$(($j+2))
        z=$(($j+9))

echo "$w, $z"

done

But my code is fail to run.

Basically I want the k and m to variable.

Can anyone address some point here?
Appreciate any help in advance.

Thanks

colucix 05-13-2012 07:28 AM

This is because brace expansion is performed before variable expansion, so that the string inside the braces is interpreted literally as
Code:

51..55
Look at this and notice the different shell expansions are performed in the order they are exposed.

In your case better to use the seq command:
Code:

for j in $(seq $k $m)
do
  ...
done

or the alternate C-like form of the for loop:
Code:

for (( j=$k; j<=$m; j++ ))
do
  ...
done

Hope this helps.

pixellany 05-13-2012 08:02 AM

this is the line with the issue:
Code:

for j in {$k..$m};do
......but, I cannot find how to do it correctly...:confused:

This works:
Code:

for j in {1..5}
is it not possible to have variable expansion in this construct???

pixellany 05-13-2012 08:04 AM

sigh....while I founder, an expert answers.....;)

David the H. 05-13-2012 08:12 AM

Two of the best pages to look at first when you come across scripting problems are the Bash Pitfalls and FAQ pages.

http://mywiki.wooledge.org/BashPitfalls
http://mywiki.wooledge.org/BashFAQ


In this case the problem is described in pitfall #33. Doing your counting with a c-style loop is usually more efficient and less prone to error anyway.

Read the excellent Bash Guide from the same source for a good tutorial on scripting basics.

http://mywiki.wooledge.org/BashGuide


Edit: BTW, when operating in arithmetic contexts, variables don't usually need to be prefixed with "$". Since string literals are invalid, they are automatically assumed to be variables and expanded.

Code:

w=$(( j+2 ))

lithos 05-13-2012 08:15 AM

May I add, that similar I had done with WHILE loop
Code:

# number of drives
DRIVESNO=$(grep 'physicaldrive' $CHECKfile | grep -c ':id')

i="0"

while [ $i -lt "$DRIVESNO" ]
do

CURDRIVE=DRIVE$i

echo "Drive $i: $(grep "physicaldrive 2:$i" $CHECKfile )" >>$RAIDSTATUSFILE
i=$[$i+1]
done

It may be that you can do it like this ?

David the H. 05-13-2012 10:04 AM

@lithos:

Seems a bit overly-complex and wasteful to me; it does exactly the same thing as c-style for loop, only less cleanly and concisely.

Also, "$[..]" is non-standard and deprecated. Use "((..))" instead, or "$((..))" if you need posix compatibility. You can also use the let keyword.

Code:

(( i++ ))        #bash or ksh form; uses ++ for simple value incrementing.
: $(( i++ ))        #posix compatible, prefixing it with the ":" (true) command keeps it from producing output.
i=$(( i + 1 ))        #using the original long syntax
let i++
let i=i+1

And if I may add a few more scripting points:

1)
Clean, consistent formatting makes code readable and more easily debuggable. Indent all your sub-commands, and separate logical sections with whitespace. Add comments anywhere the code isn't completely obvious (and remember, what seems obvious to you now will not be so a year or so down the line).

Many people also feel that it's more readable to place the "do/then" keywords on the same line as the "for/while/until/if" keywords, as it more clearly separates the outside block from the inside block.

Code:

for var in fee fai foo fum ; do

        if [[ "$var" == "foo" ]]; then
                echo "Found 'foo'."
        fi

done

2)
When using bash or ksh, it's recommended to use ((..)) for numerical tests, and [[..]] for string/file tests and other complex expressions. Avoid using the old [..] test unless you specifically need POSIX-style portability.

http://mywiki.wooledge.org/ArithmeticExpression
http://mywiki.wooledge.org/BashFAQ/031
http://wiki.bash-hackers.org/commands/classictest
http://wiki.bash-hackers.org/syntax/...nal_expression

3)
QUOTE ALL OF YOUR VARIABLE SUBSTITUTIONS! You should never leave the quotes off a parameter expansion unless you explicitly want the resulting string to be word-split by the shell (globbing patterns are also expanded). This is a vitally important concept in scripting, so train yourself to do it correctly now.

http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes

4)
Since environment variables are generally all upper-case, it's good practice to keep your own user variables in lower-case or mixed-case, to help differentiate them.


It would probably also be more efficient to save the first grep output into an array first, so that you only have to run it once. Then you could check that as needed for the values you want. I don't know what the contents of the $CHECKfile looks like, though, or else I could post an updated version.


All times are GMT -5. The time now is 09:36 PM.