user3330284
user3330284

Reputation: 383

looping two values in a for loop bash

Below is my input file, that I need to pass and find out whose value is above 10G.

100G tom
30G kelly
40G messy
50G Kyrie
1G james
.5G curry
2.4 sweety
57G muller
6G kevin

Here is the code attempt in bash.

for i in `cat test.txt`;
do
  k=$(echo $i | awk '{print $1}' | grep G | cut -d'G' -f1;);
  j=$(echo $i | grep -v '^[0-9]';);
  int=${k%.*};
  if [[ -z $int ]];
    then continue
  else
    if [ $int -ge 10 ];
    then
      # du -sh
      echo $j
      # sudo du -sh $j
    fi
  fi
# echo $int
done

It's producing results if more then 10, i.e if [ $int -ge 10 ] is working. I am not able to print the name if value is more then 10Gig in file. To put it simple my expected result is

100G tom
30G kelly
40G messy
50G Kyrie
57G muller

Upvotes: 1

Views: 953

Answers (5)

tripleee
tripleee

Reputation: 189327

Don't read lines with for. The idiomatic way to read a line with two fields is

while read -r first second; do
    : ... things
done <test.txt

But of course, you can simply do

awk '($1 ~ /G$/ && $1+0>10) || $1 ~ /[TP]$/' test.txt

(I added terabytes and petabytes just to show you how it's done if you should need it.)

Generally, looping over the lines in a file one by one in the shell is an antipattern which suggests you should try sed or Awk instead unless you really need the body of the loop to be shell script.

Upvotes: 1

AGBhat
AGBhat

Reputation: 56

You can use grep as:

egrep '^0*[1-9][0-9]+\.?[0-9]*G' file_name

Upvotes: 1

Ruslan Osmanov
Ruslan Osmanov

Reputation: 21492

Using numfmt tool (which is a part of GNU Coreutils):

while read -r line
do
    n=$(numfmt --from=auto --format %f "${line%% *}")
    (( $(bc <<< "$n > 10000000000") )) && printf '%s\n' "$line"
done < test.txt

The loop reads test.txt file line by line; -r option prevents backslashes from being interpreted. Since IFS variable is not modified, the line is trimmed, and we can safely extract the first column with an expression like "${line%% *}" which removes the first space and everything after it leaving us only the first column.

The numfmt command converts the first column to floating point format.

Since Bash does not support floating point numbers, bc is used to check if $n is greater than 10000000000. If it is, the command exits with zero status (indicating success), and the printf command is called.

Obviously, you can use the code above with other common units such as K, Ki, M, Mi etc.


Since sizes of real files are expressed in integers, you can get rid of the "floating point arithmetic" in the following way:

declare -i n=$(numfmt --from=auto --format %.0f "${line%% *}")
(( $n > 10000000000 )) && printf '%s\n' "$line"

Zero precision format %.0f means that numfmt will return the result as (rounded) integer. The second line checks if $n is greater than 10000000000 using arithmetic expansion.


On Mac OS, the numfmt tool is provided by GNU Coreutils package; the name of executable is gnumfmt.

Upvotes: 2

abhishek phukan
abhishek phukan

Reputation: 791

Can you try this :

bash-4.4$ cat filename
100G tom
30G Kely
40G messy
50G kyrie
1G james
.5G curry
2.4 sweety
57G muller
6G kevin

bash-4.4$ cat script.sh
cat filename|grep "G">tempFile
while read line;
do
size=echo $line|awk 'BEGIN{FS="G"}{print $1}'
check=echo $line|grep "^[0-9]"|wc -l
if [ $check -ne 0 ]
then
if [ $size -gt 10 ]
then
echo $line
fi
fi
done

bash-4.4$ ./script.sh
100G tom
30G Kely
40G messy
50G kyrie
57G muller

You can remove the tempfile at the end of the script if no longer required. Or it will get overwritten every time you run the script.

hope this helps.

Upvotes: 0

P....
P....

Reputation: 18351

awk 'BEGIN{FS="G| "} $1>10' inputfile
100G tom
30G kelly
40G messy
50G Kyrie
57G muller

This is using G as field separator and $1>10 is the condition to print the whole record. A while space is also used as field seprator to deal with the records like 2.4 sweety

Note: This assumes, that your input is having records only in Gigs.

Upvotes: 3

Related Questions