0

I want to get my data usage from my wifi device to display on my top bar, I can get the data usage in bytes using curl like this

$bytes=(curl -d "Page=GetWANInfo" -X POST http://jiofi.local.html/cgi-bin/qcmap_web_cgi -s| jq -r .total_data_used)

it gives me a big number like 411982397 now I want to convert it in MBs and want to display it like 411.9 MB

but I am unable to figure out how can I format that big number like this.

I tried using bc to convert it into MB echo $bytes / 1000000 | bc

but I am unable to put that into a variable it is giving me errors.

$ total=($bytes / 1000000 | bc)
bash: syntax error near unexpected token `|'
$ total=$($bytes / 1000000 | bc)
411982397: command not found
$ echo "$bytes / 1000000" | bc
411
$ total=$("$bytes / 1000000" | bc)
bash: 411982397 / 1000000: No such file or directory

my Idea here is to put that output in a variable than I can just echo $total MB

What can be a better approach for this problem? also I need to run this command every few seconds so I need a efficient solution to the problem which is easy to cpu

2 Answers2

4

jq can do the division:

$ echo '{"total_data_used":411982397}' | jq -r '.total_data_used/1e6|tostring + "MB"'
411.982397MB

Most modern shells (zsh, ksh93, yash, fish at least) can do it as well by themselves if you don't have to use bash specifically.

In zsh:

printf -v total %gMB $(( bytes / 1_000_000. ))

(note the . to force floating point arithmetic. You could also use 1e6).

ksh93's printf also has builtin support to convert to human readable formats with kMGTPE suffixes, both using 1000 based and 1024 units:

$ printf '%#dB\n' bytes
412MB
$ printf '%#iB\n' bytes
393MiB

In bash specifically, for the special case of dividing by a power of 10, you can use its printf though by appending e-6 to the integer and use it as an argument for %e, %f, %g, %a (or uppercase variants).

printf -v total %gMB "${bytes}e-6"

The default precision for %g is 6 significant digits, you can change that if you like with %.12g for instance for 12 digits. Note that printf (in both bash and zsh at least) honours the locale's decimal radix character. For instance, you'll get 411.982MB in an English locale and 411,982MB in a French/German... locale.

To get bc to do the division, you'll need to feed the expression on its stdin, either by piping the output of a command that outputs it, typically, printf is used for that¹, or by using a here-document (standard sh) or here-string (from zsh, but found in many other shells these days), and then get its output through a pipe using command substitution for instance to store into the total variable.

But you'll want to set its scale special variable which tells it how many digits after the radix to compute upon division (0 by default, unless the -l option is used in which case it's 20 instead). So:

total=$(
  printf 'scale=2\n%d / 1000000\n' "$bytes" | bc
)

Or:

total=$(
  bc << EOF
scale=2
$bytes / 1000000
EOF
)

An alternative to bc is awk which can do floating point arithmetic and format numbers with its own printf:

total=$(
  jq... | awk '{printf "%gMB", $0 / 1e6}'
)

¹ echo is also commonly used but as it's got a non-portable and unreliable API, it's best avoided in the general case to output arbitrary data

2

I think you're looking for total=$(echo "$bytes / 1000000 " | bc).

DopeGhoti
  • 76,081