LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-13-2012, 06:39 AM   #1
vjramana
Member
 
Registered: Sep 2009
Posts: 89

Rep: Reputation: 0
'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
 
Old 05-13-2012, 07:28 AM   #2
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
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.
 
Old 05-13-2012, 08:02 AM   #3
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Mint
Posts: 17,809

Rep: Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743
this is the line with the issue:
Code:
for j in {$k..$m};do
......but, I cannot find how to do it correctly...

This works:
Code:
for j in {1..5}
is it not possible to have variable expansion in this construct???
 
Old 05-13-2012, 08:04 AM   #4
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Mint
Posts: 17,809

Rep: Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743
sigh....while I founder, an expert answers.....
 
Old 05-13-2012, 08:12 AM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
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 ))

Last edited by David the H.; 05-13-2012 at 08:18 AM.
 
Old 05-13-2012, 08:15 AM   #6
lithos
Senior Member
 
Registered: Jan 2010
Location: SI : 45.9531, 15.4894
Distribution: CentOS, OpenNA/Trustix, testing desktop openSuse 12.1 /Cinnamon/KDE4.8
Posts: 1,144

Rep: Reputation: 217Reputation: 217Reputation: 217
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 ?
 
Old 05-13-2012, 10:04 AM   #7
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
@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.
 
1 members found this post helpful.
  


Reply

Tags
bash scripting



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
how to loop over text file lines within bash script for loop? johnpaulodonnell Linux - Newbie 9 07-28-2015 03:49 PM
Bash Script Loop Question SoulShaker Linux - Server 5 06-17-2009 01:44 PM
Bash script while loop problems whammack Programming 7 02-02-2007 05:31 AM
bash script loop bong.mau Programming 6 09-14-2005 07:38 PM
bash script for loop drisay Programming 5 12-25-2004 12:32 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:28 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration