Using an arithmetic expression to initialise a for loop
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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
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:
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
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
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.
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):
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
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.
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
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
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.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.