passing a float from awk to bash - bash

I need to add a non-integer counter value of a loop to the counter of another loop. like what follows:
I have a two loops like:
numi=$(awk 'BEGIN{for(i=0;i<=.4;i+=0.2)print i}')
numj=$(awk 'BEGIN{for(j=.1;j<=1;i+=0.3)print j}')
for i in $numi
do
for j in $numj
do
***then here I want to change j eg. to j+i and do blah blah but
the problem is that bash does not like float and I can't find a way
to pass the float value. As I'm running another software through this
loop and use the value to feed that software I have to do it in bash
or somehow pass the values to bash.

j+i and do blah blah but the problem is that bash does not like float
if this is your concern, see if below example helps:
$ bc<<<'3.5+1'
4.5

for i in $(seq 0 .2 .4)
do
for j in $(seq .1 .3 1)
do
j_and_i=$(($i+$j))
echo $j_and_i
done
done
The $() construction executes the command within parentheses and substitutes the results into your line. The seq command prints a sequence of numbers. In these cases it's given a FIRST, INCREMENT, and LAST values to use. seq .1 .3 1 results in "0.1 0.4 0.7 1.0".
The $(()) construction does math. $((1+1)) is 2, for example.

Related

Bash loop with multiple variables as input

I'm trying to run a command using different variables as parameters. This is written as a bash script.
for i, j, k in $(seq 2 0.1 6), $(seq 2 0.25 5.5), $(seq 1 1 10)
do
p.p_s_e r=100 a_t=S res=$i lam=$j s=$k sig=10 >> $k_lam_$j_res_$i.log
p.p_s_e r=100 a_t=S res=$i lam=$j s=$k sig=20 >> $k_lam_$j_res_$i.log
p.p_s_e r=100 a_t=S res=$i lam=$j s=$k sig=40 >> $k_lam_$j_res_$i.log
done
When I run this, the program does not take any of the values I am trying to give it. Sorry I can't be more clear about what I am trying to do. p.p_s_e is the program, the following X=y are variables, and I need to output to be written into a file. I think it's the way I am using for, do, done loops.
You just need three loops. (Four, if you add a loop to iterate over the sig values as well.)
for i in $(seq 2 0.1 6); do
for j in $(seq 2 0.25 5.5); do
for k in $(seq 1 1 10); do
for sig in 10 20 40; do
p.p_s_e r=100 a_t=S res=$1 lam=$j s=$k sig=$sig
done >> ${k}_lam_${j}_res_${i}.log
done
done
done

Bash read multiple files in for loop (as a execute arguement)

I am trying to read a file in bash forloop. But I do not know how to put write the script for this.
for i in $( seq 0 $step 10 )
do
echo "Rendering: "$(( i + j ))
python auto_fine.py density000000.vtu velocity000000.vtu $(( i + j ))
done
each and every loop I need to call
i -> 0 python auto_fine.py density000000.vtu velocity000000.vtu
i -> 1 python auto_fine.py density000010.vtu velocity000010.vtu
i -> 2 python auto_fine.py density000020.vtu velocity000020.vtu
It seems to me that you need to zero pad the numbers sed provides to you:
As seen in How to zero pad a sequence of integers in bash so that all have the same width?, you need to do something like
$ seq -f "%06g" 0 10 100
Which returns:
000000
000010
000020
...
000100
All together,
for i in $(seq -f "%06g" 0 10 100)
do
# echo "Rendering: "$(( i + j )) -- not sure what this does
python auto_fine.py density$i.vtu velocity$i.vtu
done
Bash can do this without requiring external tools like seq.
for i in {0..100}; do
[[ $i = *0 ]] || continue
python auto_fine.py density$(printf '%06d' $i).vtu velocity$(printf '%06d' $i).vtu
done
This uses pattern matching (*0) to limit your list to every 10 numbers, which is a bit of a hack, but will work against your sample data.
You could alternately loop against your zero-padded numeric strings directly:
for i in $(printf '%05d0 ' {0..10}); do
python auto_fine.py density$i.vtu velocity$i.vtu
done
This option shows you every 10 items by placing a zero in the printf format after the incrementing number, which becomes the tens digit. If you want more arbitrary sequencing, you might use multipliers, still without spawning external processes:
low=0
high=100
mult=10
for i in $(eval echo {$low..$((high/mult))}); do
n=$(printf '%06d' $((i*mult)))
python auto_fine.py density$n.vtu velocity$n.vtu
done
Note the eval, which lets you expand variables for use in your sequence expression. (If you are getting these numbers from an external source, have your script validate them before using them!)
If you're using bash version 4 (i.e. not the native version on OSX), you also have increments available in sequence expressions. From the man page:
A sequence expression takes the form {x..y[..incr]}, where x and y are
either integers or single characters, and incr, an optional increment,
is an integer.
So perhaps:
low=0
high=100
mult=10
for i in $(eval "printf '%06d ' {$low..$high..$mult}"); do
python auto_fine.py density$i.vtu velocity$i.vtu
done
Note that in sequence expressions, the first member of the sequence is the first number provided, rather than merely a product of a multiplier. We have quotes around the printf to ensure that the sequence expression is expanded by eval, and not interpreted by the command substitution ($(..)).
looping for all the files in the current dir is trivial:
for i in $( ls -1 )
do
# your code here, variable is referenced with $i
done
what's the j variable you are using?

Determining the number of decimals in a float number

I want to run a command (such as ls -lrt) 49 times and every time 20 milliseconds after the previous run. What I have written in my bash file is:
for i in `seq 1 49`;
do
v=6.$((i*20)
sleep $v && ls -lrt
done
But it apparently does not differentiate cases like where i equals to 4 with the one that i equals to 40 as both result in v=6.8. What I need is to wait 6.080 for i=4 and 6.800 for i=40.
You can use printf to format the number:
printf -v v '6.%03d' $((i*20))
-v v specifies that the variable $v should hold the result.
how about v=$(echo "scale=2;6+$i*0.02"|bc)
this will keep increasing if the result was greater than 7, although it won't happen till 49. But personally I think it is better than string concatenation.

How to loop argument in bash to call a function

I'd like to apologize if my question had already been asked, but english isn't my native language and I didn't find the answer. I'd like to have a bash script that executes a program I'll call MyProgram, and I want it to run with a fixed number of arguments which consist in random numbers. I'd like to have something like this:
./MyProgram for(i = 0; i < 1000; i++) $(($RANDOM%200-100))
How should I go about this?
You (mostly) just have the loop and the actual program call inverted.
for ((i=0; i < 1000; i++)); do
./MyProgram $((RANDOM%200 - 100))
done
If, however, you actually want 1000 different arguments passed to a single call, you have to build up a list first.
args=()
for ((i=0; i < 1000; i++)); do
args+=( $((RANDOM%200 - 100)) )
done
./MyProgram "${args[#]}"
The
$RANDOM % 200 - 100
is the same as the next perl
perl -E 'say int(200*rand() -100) for (1..1000)'
e.g. the
perl -E 'say int(200*rand() -100) for (1..1000)' | xargs -n1 ./MyProgram
will run like:
./MyProgram -10
./MyProgram 13
... 1000 times ...
./MyProgram 55
./MyProgram -31
if you need 1000 args
./MyProgram $(perl -E 'say int(200*rand() -100) for (1..1000)')
will produce
./MyProgram 5 -41 -81 -79 -14 ... 1000 numbers ... -63 -9 95 -9 -29
In addition to what #chepner says, you can also use the for ... in style of for loop. This looks like:
for a in one two three; do
echo "${a}"
done
which would produce the result:
one
two
three
In other words, the list of words after the in part, separated by spaces, is looped over, with each iteration of the loop having a different word in the variable a.
To call your program 1000 times (or just modify to produce the list of arguments to run it once as in #chepner's answer) you could then do:
for a in $(seq 1 1000); do
./MyProgram $((RANDOM%200 - 100))
done
where the output of the seq command is providing the list of values to loop over. Although the traditional for loop may be more immediately obvious to many programmers, I like for ... in because it can be applied in lots of situations. A crude and mostly pointless ls, for example:
for a in *; do
echo "${a}"
done
for ... in is probably the bit of "advanced" bash that I find the most useful, and make use of it very frequently.

echo value of 2 raised to the power of {0....5} using bash

I am new to bash scripting. Now, the question is self explanatory. I want to print the values 2^0, 2^1, 2^2, 2^3, 2^4, 2^5 using loop in bash.
I tried ..
for i in {0...5}; do echo 2^$i; done
result:
2^{0...5}
please suggest a solution
This is the correct form:
for i in {0..5}; do echo $((2**i)); done
Where { .. } is the range operator and $(( )) the arithmetical evaluation operator.
Note that the power operator in Bash is written ** and not ^.
Edit: Roberto Reale's answer is much better for this purpose, as it's shorter and simpler.
2^$i; won't work unfortunately, as bash doesn't support that operator.
You could try adding this
pow()
{
echo $(( ${1:?} ** ${2:?} ))
}
to your code (using it like pow [base] [exponent] (without the brackets of course)).
(Bare in mind I havent't tested this, so this may not work as expected)
Source
You could try this code also,
$ for i in {0..5}; do awk -v var=$i 'BEGIN{print 2^var}'; done
1
2
4
8
16
32

Resources