1

I always get

-bash: warning: command substitution: ignored null byte in input

warnings when the following code is executed:

BW=`bc <<< "$(cat $TMP | grep -Pzo '(?<="outgoing_traffic": )(.*)(?=,)')/1024^3"`

That warning also appears if the result is NOT zero.

How can i avoid that?

How can i skip that error when it's really 0?

UPDATE I tried the solution provided below:

tr -d '\0' 

but that code does not work:

BW=tr -d '\0'  < `bc <<< "$(cat $TMP | grep -Pzo '(?<="outgoing_traffic": )(.*)(?=,)')/1024^3"`

Output:

-bash: warning: command substitution: ignored null byte in input
-bash: `bc <<< "$(cat $TMP | grep -Pzo '(?<="outgoing_traffic": )(.*)(?=,)')/1024^3"`: No such file or directory

Funny side-fact, it isn't 0

BW=`bc <<< "$(cat $TMP | grep -Pzo '(?<="outgoing_traffic": )(.*)(?=,)')/1024^3"`
echo $BW

Output:

-bash: warning: command substitution: ignored null byte in input
4
tripleee
  • 175,061
  • 34
  • 275
  • 318
Berndinox
  • 23
  • 1
  • 5

1 Answers1

5

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.

tripleee
  • 175,061
  • 34
  • 275
  • 318