Why is variable being incremented? - bash

Could someone help me figure why is the variable "$valorbase" in my script being incremented. It should continue the process for the next line when "$valorbase=8", though it happens only for the first line. Then it starts incrementing the numbers and dont stop when value 8 is reached.
Thanks!
#!/bin/bash
while read -r line <&3
do
valorbase=8
valor=0
echo "$line"
echo "Valor:"
read -r valor
echo "$valor" >&5
echo "||||||""$valor""|" >&6
valordasoma=$(awk -F"|" '{ sum += $1 } END { print sum }' < soma.txt)
var=$(awk -v o1=$valordasoma -v t1=$valorbase 'BEGIN { print (o1 >= t1)?"1":"0" }' < soma.txt)
if [[ $var -ge 1 ]]
then
echo "Valor da soma > que, ou = ao valor base"
echo "Repete comando para a linha"
else [[ $var -lt 1 ]]
until [[ $var -eq 1 ]]
do
echo "Valor:"
read -r valor
echo "$valor" >&5
echo "||||||""$valor""|" >&6
valordasoma=$(awk -F"|" '{ sum += $1 } END { print sum }' < soma.txt)
var=$(awk -v o1=$valordasoma -v t1=$valorbase 'BEGIN { print (o1 >= t1)?"1":"0" }' < soma.txt)
if [[ $var -eq 1 ]]
then
> soma.txt
else
:
fi
done
fi
done 3<resultado.txt 5>soma.txt 6>partidasdobradas.txt
resultado.txt
TEST| 31|02/05/2015|6.1.1.01.001|2.1.1.01.005||8.100|DIVERSOS|||N||| ||S|CB|||05|||||||31.000|N|N|||0.000|
TEST| 34|03/05/2015|6.1.1.01.002|2.1.1.01.005||6.900|DIVERSOS|||N||| ||S|CB|||05|||||||34.000|N|N|||0.000|
TEST| 36|03/05/2015|6.1.1.01.002|2.1.1.01.005||8.900|DIVERSOS|||N||| ||S|CB|||05|||||||36.000|N|N|||0.000|
TEST| 38|04/05/2015|6.1.1.01.001|2.1.1.01.005||13.490|DIVERSOS|||N||| ||S|CB|||05|||||||38.000|N|N|||0.000|
TEST| 64|12/05/2015|6.1.1.01.001|2.1.1.01.005||6.780|DIVERSOS|||N||| ||S|CB|||05|||||||64.000|N|N|||0.000|

When you write to soma.txt using >&5 inside the loop, it writes to the file at the current position in the file. When you truncate the file with > soma.txt, the current position isn't reset, so future writes go into the middle of the file, with a bunch of nulls at the beginning.
You should truncate the file before the loop, then use 5>>soma.txt as the redirection of the loop, so it will write in append mode. This will make it automatically seek to the current end of the file.
#!/bin/bash
>soma.txt
while read -r line <&3
do
valorbase=8
valor=0
echo "$line"
echo "Valor:"
read -r valor
echo "$valor" >&5
echo "||||||""$valor""|" >&6
valordasoma=$(awk -F"|" '{ sum += $1 } END { print sum }' < soma.txt)
var=$(awk -v o1=$valordasoma -v t1=$valorbase 'BEGIN { print (o1 >= t1)?"1":"0" }' < soma.txt)
if [[ $var -ge 1 ]]
then
echo "Valor da soma > que, ou = ao valor base"
echo "Repete comando para a linha"
else [[ $var -lt 1 ]]
until [[ $var -eq 1 ]]
do
echo "Valor:"
read -r valor
echo "$valor" >&5
echo "||||||""$valor""|" >&6
valordasoma=$(awk -F"|" '{ sum += $1 } END { print sum }' < soma.txt)
var=$(awk -v o1=$valordasoma -v t1=$valorbase 'BEGIN { print (o1 >= t1)?"1":"0" }' < soma.txt)
if [[ $var -eq 1 ]]
then
> soma.txt
else
:
fi
done
fi
done 3<resultado.txt 5>>soma.txt 6>partidasdobradas.txt

Related

Convert string in Shell

I have a following varaible:
tags = {
environment = "development",
provider = "ServiceOne",
ansible_role = "nfs-role",
comment = "mysql"
}
In my pipeline i need to convert it to the following:
tfh pushvars -overwrite-all -dry-run false -hcl-var "tags={environment=\"development\", provider=\"ServiceOne\", ansible_role=\"nfs-rolep\",comment= \"mysql\"}"
I have tried with SED and AWK but couldn't get any result?
This is where i am standing now:
#!/bin/bash
#[[ -z "$2" ]] && echo "==> Usage: ./transform_tfe_vars.sh <<INPUT_FILE>> <<OUTPUT_FILE>>" && exit 1;
vars_file=${1}
#output_file=${2}
tmp_file=".todelete.tmp"
cmd "$vars_file" | grep -v '^#' | awk '!/^$/' > "$tmp_file"
while read -r p; do
a=$(echo "$p" | awk '{print $1}')
b=$(echo "$p" | awk '{print $3}')
echo "tfh pushvars -overwrite-all -dry-run false -shcl-var \"$a=\\""$b""\""
done <$tmp_file
A shell read loop is always the wrong approach for manipulating text, see why-is-using-a-shell-loop-to-process-text-considered-bad-practice. The guys who invented shell also invented awk for shell to call to manipulate text.
It looks like this might be what you're trying to do:
#!/usr/bin/env bash
(( $# == 2 )) || { echo "==> Usage: ${0##*/} <<INPUT_FILE>> <<OUTPUT_FILE>>"; exit 1; }
vars_file="$1"
output_file="$2"
awk '
BEGIN {
ORS = ""
print "tfh pushvars -overwrite-all -dry-run false -hcl-var \""
}
NF && !/^#/ {
gsub(/[[:space:]]/,"")
gsub(/"/,"\\\\&")
print
}
END {
print "\"\n"
}
' "$vars_file" > "$output_file"

Code to count the number of sequential characters

For example, if the input is aabcca, the output needs to be a2b1c2a1 not a3b1c2
I originally wrote this -
echo "aabcca" > file.txt
a=0
b=0
c=0
while IFS= read -r -n1 char
do
[ "$char" == "a" ] && (( a++ ))
[ "$char" == "b" ] && (( b++ ))
[ "$char" == "c" ] && (( c++ ))
done < file.txt
echo "a${a}b${b}c${c}"
But this outputs a3b1c2. I want a2b1c2a1.
Using awk, you may do this:
awk '{
p=c=""
for (i=1; i<=length(); ++i) {
f=substr($0, i, 1)
if (p != "" && f != p) {
printf "%s", p c
c = 0
}
++c
p = f
}
print p c
}' file.txt
a2b1c2a1
How about:
#!/usr/bin/env bash
count=0
read -r -n1 prev_char < file.txt
while IFS= read -r -n1 char
do
if [ "$prev_char" != "$char" ]
then
printf "%c%d" "$prev_char" "$count"
count=0
fi
prev_char="$char"
count=$((count + 1))
done < file.txt
printf "\n"
Here's an one-liner way to do it:
tr '\n' ' ' < file.txt | fold -w1 | uniq -c | awk '$2!=""{printf "%s", $2 $1} END {printf "\n"}'
EDIT: Also if you want to get rid of punctuation characters, just add this to tr:
tr '\n[:punct:]' ' ' < file.txt | fold -w1 | uniq -c | awk '$2!=""{printf "%s", $2 $1} END {printf "\n"}'

check if a file contains two variables in a line

I am trying to check the values of my variables are exist in the file or not using if condition in Bash.
I tried is as follows, but for all the values I am getting value false.
a=-127.5256
b=24.5632
file=test.txt
-54.2565 58.9685
-127.2568 12.5890
-127.5256 24.5632
-78.9865 35.2366
I tried as follow but not working in my case:
if grep -Fxq "($a $b | bc)" $file; then
echo True
else
echo False
Is there any other way to perform the above job?
Thank you
I would prefer to use AWK.
awk -v a=-127.5256 -v b=24.5632 '{if ($1==a && $2=b) print "True"}' < input file
using bash
while IFS=" " read -r f1 f2;
do
if [ "$a" == "$f1" ] && [ "$b" == "$f2" ]
then
echo "True"
fi
done < input file
Demo:
$cat test.txt
-54.2565 58.9685
-127.2568 12.5890
-127.5256 24.5632
-78.9865 35.2366
$awk -v a=-127.5256 -v b=24.5632 '{if ($1==a && $2=b) print "True"}' test.txt
True
$echo $a $b
-127.5256 24.5632
$while IFS=" " read -r f1 f2;
> do
> if [ "$a" == "$f1" ] && [ "$b" == "$f2" ]
> then
> echo "True"
> fi
> done < test.txt
True
$

bash compare the numeric value of multiple columns

i have a variable which it output yileds 2 columns:
echo "$SIZE_TO_SOCKET"
A 256
B 256
My gloal is basically to compare the 2 numbers and print a massage
somthing like :if they match : Success: A(256) is euqal to B(256)
or Error: A(256) is not euqal to B(256) if there is the numbers are not euqal
My code is:
while IFS= read -r i;do
SIZE=$(echo "$i"|awk '{print $2}')
SOCKET=$(echo "$i"|awk '{print $1}')
if [[ "$SOCKET" = "A" ]] ; then
SOCKET_A="$SIZE"
elif [[ "$SOCKET" = "B" ]] ; then
SOCKET_B="$SIZE"
fi
if [[ $SOCKET_A -ne $SOCKET_B]];then
echo "error: SOCKET_A is not equal to SOCKET_B"
elif [[ $SOCKET_A -eq $SOCKET_B]];then
cho "success: SOCKET_A is equal to SOCKET_B"
fi
done <<< "$SIZE_TO_SOCKET"
the code doesn't yields any output ,anyway there is properly shorter and more elegant way
input="A 256\nB 256"
arr=($(echo -e "$input"))
if [[ "${arr[1]}" -eq "${arr[3]}" ]]
then
echo "success: ${arr[0]}(${arr[1]}) is equal to ${arr[2]}(${arr[3]})"
else
echo "error: ${arr[0]}(${arr[1]}) is not equal to ${arr[2]}(${arr[3]})"
fi
Replace the input variable by your input and this script outputs either
success: A(256) is equal to B(256)
for two same numbers or
error: A(257) is not equal to B(256)
for two different numbers.
This was pretty straightforward solution I ended up with:
line1=$(echo "$SIZE_TO_SOCKET" | awk 'NR == 1')
line2=$(echo "$SIZE_TO_SOCKET" | awk 'NR == 2')
key1=$(echo "$line1" | cut -d ' ' -f 1)
value1=$(echo "$line1" | cut -d ' ' -f 2)
key2=$(echo "$line2" | cut -d ' ' -f 1)
value2=$(echo "$line2" | cut -d ' ' -f 2)
if [[ $value1 -eq $value2 ]]; then
echo "Success: $key1($value1) is equal to $key2($value2)"
else
echo "Error: $key1($value1) is not equal to $key2($value2)"
fi
What is wrong with your code?:
your code "corrected" would be:
SIZE_TO_SOCKET=$(printf '41203235360a42203235360a' | xxd -p -r)
while IFS= read -r i;do
SIZE=$(echo "$i"|awk '{print $2}')
SOCKET=$(echo "$i"|awk '{print $1}')
if [[ "$SOCKET" = "A" ]] ; then
SOCKET_A="$SIZE"
elif [[ "$SOCKET" = "B" ]] ; then
SOCKET_B="$SIZE"
fi
if [[ $SOCKET_A -ne $SOCKET_B ]] ; then
echo "error: SOCKET_A is not equal to SOCKET_B"
elif [[ $SOCKET_A -eq $SOCKET_B ]] ; then
echo "success: SOCKET_A is equal to SOCKET_B"
fi
done <<< "$SIZE_TO_SOCKET"
you needed spaces in different places like this one $SOCKET_B ]] ; then (your original code is $SOCKET_B]];then)
the output of your "corrected" code is:
error: SOCKET_A is not equal to SOCKET_B
success: SOCKET_A is equal to SOCKET_B
if you use bash -x YOUR_SCRIPT, you get:
++ printf 41203235360a42203235360a
++ xxd -p -r
+ SIZE_TO_SOCKET='A 256
B 256'
+ IFS=
+ read -r i
++ echo 'A 256'
++ awk '{print $2}'
+ SIZE=256
++ echo 'A 256'
++ awk '{print $1}'
+ SOCKET=A
+ [[ A = \A ]]
+ SOCKET_A=256
+ [[ 256 -ne '' ]]
+ echo 'error: SOCKET_A is not equal to SOCKET_B'
error: SOCKET_A is not equal to SOCKET_B
+ IFS=
+ read -r i
++ echo 'B 256'
++ awk '{print $2}'
+ SIZE=256
++ echo 'B 256'
++ awk '{print $1}'
+ SOCKET=B
+ [[ B = \A ]]
+ [[ B = \B ]]
+ SOCKET_B=256
+ [[ 256 -ne 256 ]]
+ [[ 256 -eq 256 ]]
+ echo 'success: SOCKET_A is equal to SOCKET_B'
success: SOCKET_A is equal to SOCKET_B
+ IFS=
+ read -r i
read that carefully; you have an error in your logic.
this could be the corrected version of your code:
SIZE_TO_SOCKET=$(printf '41203235360a42203235360a' | xxd -p -r)
while IFS= read -r i;do
SIZE=$(echo "$i"|awk '{print $2}')
SOCKET=$(echo "$i"|awk '{print $1}')
if [[ "$SOCKET" = "A" ]] ; then
SOCKET_A="$SIZE"
elif [[ "$SOCKET" = "B" ]] ; then
SOCKET_B="$SIZE"
fi
done <<< "$SIZE_TO_SOCKET"
if [[ $SOCKET_A -ne $SOCKET_B ]] ; then
echo "error: SOCKET_A is not equal to SOCKET_B"
elif [[ $SOCKET_A -eq $SOCKET_B ]] ; then
echo "success: SOCKET_A is equal to SOCKET_B"
fi
the output is:
success: SOCKET_A is equal to SOCKET_B
and if you use bash -x YOUR_CORRECTED_SCRIPT, you get:
++ printf 41203235360a42203235360a
++ xxd -p -r
+ SIZE_TO_SOCKET='A 256
B 256'
+ IFS=
+ read -r i
++ echo 'A 256'
++ awk '{print $2}'
+ SIZE=256
++ echo 'A 256'
++ awk '{print $1}'
+ SOCKET=A
+ [[ A = \A ]]
+ SOCKET_A=256
+ IFS=
+ read -r i
++ echo 'B 256'
++ awk '{print $2}'
+ SIZE=256
++ echo 'B 256'
++ awk '{print $1}'
+ SOCKET=B
+ [[ B = \A ]]
+ [[ B = \B ]]
+ SOCKET_B=256
+ IFS=
+ read -r i
+ [[ 256 -ne 256 ]]
+ [[ 256 -eq 256 ]]
+ echo 'success: SOCKET_A is equal to SOCKET_B'
success: SOCKET_A is equal to SOCKET_B

Using 'if' within a 'while' loop in Bash

I have these diff results saved to a file:
bash-3.00$ cat /tmp/voo
18633a18634
> sashabrokerSTP
18634a18636
> sashatraderSTP
21545a21548
> yheemustr
I just really need the logins:
bash-3.00$ cat /tmp/voo | egrep ">|<"
> sashaSTP
> sasha
> yhee
bash-3.00$
But when I try to iterate through them and just print the names I get errors.
I just do not understand the fundamentals of using "if" with "while loops".
Ultimately, I want to use the while loop because I want to do something to the lines - and apparently while only loads one line into memory at a time, as opposed to the whole file at once.
bash-3.00$ while read line; do if [[ $line =~ "<" ]] ; then echo $line ; fi ; done < /tmp/voo
bash-3.00$
bash-3.00$
bash-3.00$ while read line; do if [[ egrep "<" $line ]] ; then echo $line ; fi ; done < /tmp/voo
bash: conditional binary operator expected
bash: syntax error near `"<"'
bash-3.00$
bash-3.00$ while read line; do if [[ egrep ">|<" $line ]] ; then echo $line ; fi ; done < /tmp/voo
bash: conditional binary operator expected
bash: syntax error near `|<"'
bash-3.00$
There has to be a way to loop through the file and then do something to each line. Like this:
bash-3.00$ while read line; do if [[ $line =~ ">" ]];
then echo $line | tr ">" "+" ;
if [[ $line =~ "<" ]];
then echo $line | tr "<" "-" ;
fi ;
fi ;
done < /tmp/voo
+ sashab
+ sashat
+ yhee
bash-3.00$
You should be checking for >, not <, no?
while read line; do
if [[ $line =~ ">" ]]; then
echo $line
fi
done < /tmp/voo
Do you really need regex here? The following shell glob can also work:
while read line; do [[ "$line" == ">"* ]] && echo "$line"; done < /tmp/voo
OR use AWK:
awk '/^>/ { print "processing: " $0 }' /tmp/voo
grep will do:
$ grep -oP '> \K\w+' <<END
18633a18634
> sashabrokerSTP
18634a18636
> sashatraderSTP
21545a21548
> yheemustr
END
sashabrokerSTP
sashatraderSTP
yheemustr

Resources