LinuxQuestions.org
Review your favorite Linux distribution.
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 11-01-2016, 04:54 PM   #1
botleybat
LQ Newbie
 
Registered: Oct 2016
Posts: 4

Rep: Reputation: Disabled
Wink Using an arithmetic expression to initialise a for loop


I have a script to be compiled in bash, with a for loop whose counting variable needs to be initialised to an expression (or function) of a variable in the program:

The relevant line is

Quote:
for (( j = $(( $line+1 )) ; j <= $(( $line+23 )) ; j++ )) ; do
I'm pretty certain this is the problem line since the shell complains about this line (number 33)

Quote:
./script.sh: line 33: 11

The first value of '$line' the loop is meant to read = 11.
So I'm assuming the for loop can't parse the expression to assign to j.

I couldn't find a solved example of a for loop used with a variable like this, but there is a way, right?

I know it's an ugly script - when I've learnt Fortran and Python I know my problems are all going to float away

There is also something else the compiler doesn't like:

Quote:
syntax error in expression (error token is "36
The second value of $line intended = 36, but I don't know if this complaint is to do with the for loop syntax, or the following awk statement which assigns a value to variable E.

Here's the whole program, and I've attached the file that the script is supposed to handle, so one can hopefully see the intention behind it; to process the recurring lists of floating point numbers in file.

I think I may also need to declare the variable "$temp" but that's a side issue....

Quote:
#!/bin/bash

for (( a = 200 ; a <= 700 ; a+=2 )) ; do
i=$(bc <<<"scale=2; $a / 100" )
cat >Si2.cell <<!
%block lattice_cart
$i $i 0.0
$i 0.0 $i
0.0 $i $i
%endblock lattice_cart
%block positions_frac
Si 0.00 0.00 0.00
Si 0.25 0.25 0.25
%endblock positions_frac
%BLOCK BS_KPOINT_PATH
0.0000 0.0000 0.0000 ! G
0.5000 0.0000 0.5000 ! X
0.5000 0.2500 0.7500 ! W
0.3750 0.3750 0.7500 ! K
0.0000 0.0000 0.0000 ! G
0.5000 0.5000 0.5000 ! L
0.6250 0.6250 0.6250 ! U
0.5000 0.2500 0.7500 ! W
0.5000 0.5000 0.5000 ! L
0.3750 0.3750 0.7500 ! K
%ENDBLOCK BS_KPOINT_PATH
!
mpirun -n 4 castep.mpi Si2
if [ -e Si2.bands ]
then
e=$(awk '/Fermi energy/ { print $6 }' Si2.bands)
line=$(awk '/Spin component/ { print NR }' Si2.bands)
for (( j = $(( $line+1 )) ; j <= $(( $line+23 )) ; j++ )) ; do
E=$(awk -v L="$j" '{if (NR==L) {print $0}}' Si2.bands)
if [ "$E" -gt "$e" ]
then
gap=$(bc <<<"scale=5; $E - $e" )
if [ "$gap" -gt "$temp" ]
then
$temp == $gap
fi
fi
done
echo $i,$gap >> lattice_bandgap.txt
fi
done
Attached Files
File Type: txt file.txt (41.7 KB, 12 views)
 
Old 11-01-2016, 06:39 PM   #2
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,680

Rep: Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894
Code:
line=$(awk '/Spin component/ { print NR }' Si2.bands)]
$line will contain the line number of each occurrence i.e
11 36 ...

You could use a for loop to iterate
Code:
for i in $line
do
  for (( j = $(( $i+1 )) ; j <= $(( $i+23 )) ; j++ )); do
  ....
  done
done
 
Old 11-01-2016, 09:00 PM   #3
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,005

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
My question would be are you planning on acknowledging anything posted in response to your question, unlike your previous question which you seemed to have abandoned?

Until I see a reply, the only additional information I would add is that all additional brackets in the for loop call are not required:
Code:
for (( j = i + 1; j <= i + 23; j++ ))
 
Old 11-02-2016, 12:05 AM   #4
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,263
Blog Entries: 24

Rep: Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194
Welcome to LQ!

As pointed out by others above, this line...

Code:
for (( j = $(( $line+1 )) ; j <= $(( $line+23 )) ; j++ )) ; do
...is overly complex. Something like this should do.

Code:
for (( j=line+1 ; j<=line+23 ; j++ )); do
To understand the differences you should understand the following points...

1. The ((...)) syntax is bash-ese for arithmetic evaluation. It evaluates one or more comma separated arithmetic expressions and returns a status - not the result of the arithmetic expression.

You can find details in man bash: ARITHMETIC EVALUATION, or here. Note that it is exactly equivalent to using the let statement to evaluate arithmetic expresions.

2. The $((...)) syntax is bash-ese for arithmetic expansion. It evaluates an enclosed arithmetic expression and returns the result, not the status.

You can also find details in man bash: ARITHMETIC EXPANSION, or here.

3. The for ((...)); do syntax is intentionally based on the arithmetic evaluation model.

Quote:
Originally Posted by botleybat View Post
I know it's an ugly script - when I've learnt Fortran and Python I know my problems are all going to float away
If that is a real expectation, you may be disappointed!

There is no magic programming language that replaces the necessity for the programmer to understand their problem space and be able to express it in code! There are many factors that make one languge more suited to certain tasks and environments than others, but there is no universal "best" language.

Shell scripting is really useful and powerful, and not inherently more difficult to use for appropriate tasks.

I would also ask you to consider grail's point about interacting with those who respond to your questions. You will find the members here willing to provide excellent answers to your questions, but it is a bit discourteous to ask for help and then ignore those who respond. Active participation in the discussion helps others to help you!

Please review the LQ Rules and FAQ's and become a participating member of the great LQ community!

Last edited by astrogeek; 11-02-2016 at 12:12 AM. Reason: tpos, typs, typos
 
Old 11-02-2016, 04:13 AM   #5
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,680

Rep: Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894
There is nothing wrong with the for loop as is. I have not examined the code completely but it looks like the OP wants to process the data between each occurrence of "spin component". The OP does not know how to deal with the results returned by awk.
 
Old 11-02-2016, 04:48 AM   #6
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,804

Rep: Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306
please use [code][/code] instead of [quote][/quote], your post will be more readable!
Please add set -xv at the beginning of your script to see what's happening (that will not solve anything) as it was already mentioned several times: http://www.linuxquestions.org/questi...0/#post5617104
Code:
#!/bin/bash
set -xv
....
and finally:
Code:
$temp == $gap
is definitely not ok (in your posted script). You need single = and no need to use $ at the beginning (also spaces are not allowed):
Code:
temp="$gap"
 
Old 11-03-2016, 07:30 AM   #7
botleybat
LQ Newbie
 
Registered: Oct 2016
Posts: 4

Original Poster
Rep: Reputation: Disabled
So now, after tending to the issues raised by michaelk, pan64 and grail, there appears to be a remaining error in the code confined to the use of 'bc' which I added to the second 'if' statement (since I read elsewhere that only integer comparison is permitted by default in bash control statements?)

This error message, on researching, is usually attributed to the bc command (unless I'm missing something),

Quote:
(standard_in) 2: parse error
Here's the latest version of the code.
I found workarounds to get a simpler version to do a less comprehensive processing of my input file and in the OP.
However I'm still hoping to get the original version working.

Sorry for not acknowledging your replies sooner, I fell ill suddenly yesterday (better now )
Code:
#!/bin/bash

for (( a = 200 ; a <= 700 ; a+=2 )) ; do
i=$(bc <<<"scale=2; $a / 100" )
cat >Si2.cell <<!
%block lattice_cart
$i $i 0.0
$i 0.0 $i
0.0 $i $i
%endblock lattice_cart
%block positions_frac
Si 0.00 0.00 0.00
Si 0.25 0.25 0.25
%endblock positions_frac
%BLOCK BS_KPOINT_PATH
0.0000 0.0000 0.0000 ! G
0.5000 0.0000 0.5000 ! X
0.5000 0.2500 0.7500 ! W
0.3750 0.3750 0.7500 ! K
0.0000 0.0000 0.0000 ! G
0.5000 0.5000 0.5000 ! L
0.6250 0.6250 0.6250 ! U
0.5000 0.2500 0.7500 ! W
0.5000 0.5000 0.5000 ! L
0.3750 0.3750 0.7500 ! K
%ENDBLOCK BS_KPOINT_PATH
!
mpirun -n 4 castep.mpi Si2
if [ -e Si2.bands ]
then
  e=$(awk '/Fermi energy/ { print $6"00" }' Si2.bands)
  line=$(awk '/Spin component/ { print NR }' Si2.bands)
   for k in $line
   do 
    for (( j=k+1 ; j<=k+23 ; j++ )) ; do
      echo $j
      E=$(awk -v L="$j" '{if (NR==L) {print $0}}' Si2.bands)
       echo $E
       if (( $(bc <<< "$E > $e") ))
       then
         gap=$(bc <<< "$E - $e" )
         if (( $(bc <<< "$gap > $temp") ))
         then
           $temp==$gap
         fi
       fi 
    done
    done
echo $i,$gap >> lattice_bandgap.txt
fi
rm Si2.bands  
done
 
Old 11-03-2016, 08:19 AM   #8
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,804

Rep: Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306
the cycle:
Code:
for (( a = 200 ; a <= 700 ; a+=2 )) ; do
    i=$(bc <<<"scale=2; $a / 100" )
done
works for me, so it is not related to bc from my side.
Did you try set -xv already?
 
Old 11-03-2016, 08:34 AM   #9
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,680

Rep: Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894
At a glance temp does not have an initial value and you still did not fix the $temp==$gap error as posted above. That should be a syntax error so not sure what is causing the parse error but see if those fix your problems.

FYI The (standard_in) 2: parse error is not referencing line 2.

Last edited by michaelk; 11-03-2016 at 08:38 AM.
 
Old 11-09-2016, 07:42 AM   #10
botleybat
LQ Newbie
 
Registered: Oct 2016
Posts: 4

Original Poster
Rep: Reputation: Disabled
Quote:
FYI The (standard_in) 2: parse error is not referencing line 2.
Is there a way to know precisely what is being referenced with this error description?

If I am interpreting the output obtained from the 'set -xv' command correctly, one of the bc statements is being referenced:

Quote:
152
awk -v L="$j" '{if (NR==L) {print $0}}' Si2.bands
++ awk -v L=152 '{if (NR==L) {print $0}}' Si2.bands
+ E=' 1.70183374'
+ echo 1.70183374
1.70183374
bc <<< "$E > $e"
++ bc
+ (( 1 ))
bc <<< "$E - $e"
++ bc
+ gap=1.14595674
bc <<< "$gap > $temp"
++ bc
(standard_in) 2: parse error
+ (( ))
+ (( j++ ))
+ (( j<=k+23 ))
+ echo 153
153
Apologies for not finding the time to keep this thread ticking.
 
Old 11-09-2016, 07:49 AM   #11
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,804

Rep: Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306Reputation: 7306
Code:
bc <<< "$gap > $temp"
++ bc
(standard_in) 2: parse error
http://www.linuxquestions.org/questi...3/#post5626462
 
Old 11-09-2016, 07:56 AM   #12
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,680

Rep: Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894Reputation: 5894
Another way of stating the same thing is $temp is undefined and therefore bc outputs a parse error.
 
Old 12-04-2016, 01:01 PM   #13
Lsatenstein
Member
 
Registered: Jul 2005
Location: Montreal Canada
Distribution: Fedora 31and Tumbleweed) Gnome versions
Posts: 311
Blog Entries: 1

Rep: Reputation: 59
Sometimes it is important to unconfuse bash by putting braces around variables of more than one letter.
and there is a difference between $line+1 and $line + 1
eg

for (( j = $(( $line+1 )) ; j <= $(( $line+23 )) ; j++ )) ; do


becomes
for (( j = $(( ${line} + 1 )) ; j <= $(( ${line} + 23 )) ; j++ )) ; do
 
Old 12-04-2016, 02:29 PM   #14
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,005

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Quote:
Originally Posted by Lsatenstein View Post
Sometimes it is important to unconfuse bash by putting braces around variables of more than one letter.
and there is a difference between $line+1 and $line + 1
eg

for (( j = $(( $line+1 )) ; j <= $(( $line+23 )) ; j++ )) ; do


becomes
for (( j = $(( ${line} + 1 )) ; j <= $(( ${line} + 23 )) ; j++ )) ; do
If you look at my example you will see you not only don't need the braces, but you don't need the dollar sign or any of the additional round brackets.
Generally the curly braces only really help if you need to identify where the variable is to end, so as to not join additional characters or to perform some kind
of parameter alteration.
 
Old 12-10-2016, 09:38 AM   #15
Fat_Elvis
Member
 
Registered: Oct 2016
Distribution: FreeDOS 1.2
Posts: 309

Rep: Reputation: 92
Quote:
Originally Posted by grail View Post
Until I see a reply, the only additional information I would add is that all additional brackets in the for loop call are not required:
Code:
for (( j = i + 1; j <= i + 23; j++ ))
Ummm, this.

The C-yet-not-quite syntax is a headache. Ugh.

Also, have you thought about picking up the practice of indenting with tabs?

Last edited by Fat_Elvis; 12-10-2016 at 09:42 AM.
 
  


Reply



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
[SOLVED] Arithmetic (bc) within for loop januka Programming 3 10-22-2012 07:26 PM
expression value in Perl's while loop password636 Programming 16 08-30-2011 09:36 PM
[SOLVED] Bash: syntax for ((<arithmetic expression>)) usage? catkin Programming 6 03-18-2010 10:58 AM
Contents of Directory Displayed using Arithmetic Expression Mr. ameya sathe Programming 3 01-26-2008 11:04 AM
bash, for loop, and arithmetic rmount Programming 13 05-23-2007 01:27 AM

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

All times are GMT -5. The time now is 02:08 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