You get the warning because grep -z
outputs a zero byte at the end of the result, and the shell can't cope with that. The trivial solution is to drop the option, or find a way to replace it with something that the shell actually can handle. Actually, it doesn't seem to serve any useful purpose here ... but probably lose the useless cat
and use modern command substitution syntax instead of the obsolescent backticks, and fix the quoting.
BW=$(bc <<< "$(grep -Po '(?<="outgoing_traffic": )(.*)(?=,)' <"$TMP")/1024^3")
As an aside, one reason your tr
command would not work was that you dropped the backticks. Also, the symbol after <
needs to be a file name. The proper syntax would look like
BW=$(bc <<< "$(grep -Pzo '(?<="outgoing_traffic": )(.*)(?=,)' <"$TMP" | tr -d '\0')/1024^3")
but as indicated above, just don't put the -z
option if you don't want a zero byte.
The reason zero bytes are sometimes useful is that if you are printing file names, that is the only character which is not allowed in file names, so it is useful as a separator when you are dealing with files. (Beginners are often intrigued that Unix file names can contain quotes and newlines etc; but they can. This is probably the #1 cause of bugs in shell scripts - beginners tend to only test on trivial file names, and produce code which breaks with real-world files.)
Just to spell this out, a zero byte is not the number 0; it is a character whose ASCII code is zero. (So it is the character before ctrl-A which is ASCII code 1, etc. Sometimes you see it referred to as ctrl-@.) You can see it in a hex dump, for example:
bash$ echo hello | tr '\n' '\0' | xxd
00000000: 6865 6c6c 6f00 hello.
The above command replaces the newline with a zero byte (ASCII code hex 00). You could leave out the tr
to see the ASCII code for the newline (hex 0A, aka ctrl-J).
Tangentially, the difference between
bc <<<"one"
and
bc <"two"
is that the latter says to read input from the file two
whereas the first simply passes the string one
as standard input to bc
. There is also <<separator
which provides literal text up to the next occurrence of separator
alone on a line as standard input to the command (known as a "here document").
So this
echo 2/3 | bc
is equivalent to
echo 2/3 > file
bc <file
rm file
or
cat <<here >file
2/3
here
bc <file
rm file
or
bc <<<2/3
except there is no physical file in the first example or the last example, and the last example is Bash only, whereas the others are compatible with any Bourne-family shell. Probably read an introduction to redirection if you need to write any more shell script.