drjrm3
drjrm3

Reputation: 4718

Use awk replace string by multiplication

I have a script that when I finally pipe to

awk -F'[()]' '{
printf("%s %s\n", $2, $4)
}'

returns

251.393GB 103.005GB
245.296GB 101.992GB
250.526GB 103.639GB
259.158GB 112.549GB
245.266GB 102.415GB
325.020GB 129.041GB
245.135GB 102.086GB
250.583GB 103.758GB
244.247GB 103.268GB
251.256GB 104.008GB
244.496GB 102.643GB
265.133GB 113.523GB
250.332GB 103.556GB
319.579GB 127.401GB
250.140GB 103.722GB
244.765GB 102.541GB

However, I would like to convert GB (which I have found acts as 1024^3) to MB (which I would like to express as 1000^2).

Using awk, how can I detect the unit (GB, MB, etc.) and convert it to the appropriate related unit using 1000 instead of 1024? In essence I would like to simply treat GB as *(1024*1024*1024)/(1000*1000)

Upvotes: 0

Views: 982

Answers (4)

shellter
shellter

Reputation: 37298

How about

echo "319.579GB 127.401GB" \
| awk '{sub(/GB$/,"",$1);sub(/GB$/,"",$2);printf("%.3f\t%.3f\n", $1*(1024*1024*1024)/(1000*1000) , $2*(1024*1024*1024)/(1000*1000))}'

output

43145.338      136795.782

The same for a file

awk '{sub(/GB$/,"",$1);sub(/GB$/,"",$2)
  printf("%.3f\t%.3f\n", $1*(1024*1024*1024)/(1000*1000) , $2*(1024*1024*1024)/(1000*1000))}'  file

You can adjust the decimal precision but changing the .3 value, or leave it off altogehter if you just want an integer value.

sub(...) works by matching GB at the end of the line $, and replaces with empty string ("") for the named column (i.e. $1 or $2). sub will accept any string value in the 3rd field, so "strGB", arr[1], arr[key]` and others will work also.

Upvotes: 0

webb
webb

Reputation: 4340

first, precalculate the multiplier:

awk 'BEGIN{print (1024*1024*1024)/(1000*1000)}'
1073.74

then find fields with "GB", multiply them, and append "MB".

awk '{
  if($1~"GB") $1=1073.74*$1"MB"
  if($2~"GB") $2=1073.74*$2"MB"
  print $1, $2
}'

(both GNU awk and awk handle math on strings by only considering the number characters, e.g., "123.45GB" * 10 yields 1234.5)

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 204035

$ cat file
251.393GB 103.005GB
245.296GB 101.992GB
250.526GB 103.639GB

$ awk '{for (i=1;i<=NF;i++) printf "%sMB%s", $i * ($i~/GB/ ? 1073.4 : 1), (i<NF ? OFS : ORS)}' file
269845MB 110566MB
263301MB 109478MB
268915MB 111246MB

or if you prefer:

$ awk '{for (i=1;i<=NF;i++) printf "%.3fMB%s", $i * ($i~/GB/ ? 1073.4 : 1), (i<NF ? OFS : ORS)}' file
269845.246MB 110565.567MB
263300.726MB 109478.213MB
268914.608MB 111246.103MB

Upvotes: 2

Sundeep
Sundeep

Reputation: 23677

Solution using perl where the e flag comes handy in such cases

$ cat ip.txt 
251.393GB 103.005GB
245.296GB 101.992GB
250.526GB 103.639GB

Without limiting decimal precision

$ perl -pe 's|([0-9.]+)GB|$1*(1024*1024*1024)/(1000*1000)|ge' ip.txt 
269931.178360832 110600.77658112
263384.574459904 109513.076113408
269000.244199424 111281.528897536

With precision

$ perl -pe 's|([0-9.]+)GB|sprintf "%.3f",$1*(1024*1024*1024)/(1000*1000)|ge' ip.txt 
269931.178 110600.777
263384.574 109513.076
269000.244 111281.529

Pre-calculating factor

$ perl -pe 'BEGIN{$m=(1024*1024*1024)/(1000*1000)} s|([0-9.]+)GB|sprintf "%.3f",$1*$m|ge' ip.txt
269931.178 110600.777
263384.574 109513.076
269000.244 111281.529

To print MB in output as well, use %.3fMB

Upvotes: 1

Related Questions