-bash:警告:命令替换:忽略输入中的空字节

Ber*_*nox 1 variables bash calculation

我总是得到

-bash: warning: command substitution: ignored null byte in input
Run Code Online (Sandbox Code Playgroud)

执行以下代码时出现警告:

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

如果结果不为零,也会出现该警告。

我怎样才能避免这种情况?

当它确实为 0 时,我怎样才能跳过该错误?

更新我尝试了下面提供的解决方案:

tr -d '\0' 
Run Code Online (Sandbox Code Playgroud)

但该代码不起作用:

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

输出:

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

有趣的侧面事实,它不是 0

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

输出:

-bash: warning: command substitution: ignored null byte in input
4
Run Code Online (Sandbox Code Playgroud)

tri*_*eee 5

您收到警告是因为grep -z在结果末尾输出一个零字节,而 shell 无法处理该情况。最简单的解决方案是删除该选项,或者找到一种方法将其替换为 shell 实际可以处理的选项。实际上,它似乎在这里没有任何有用的目的......但可能会失去无用cat并使用现代命令替换语法而不是过时的反引号,并修复引用。

BW=$(bc <<< "$(grep -Po '(?<="outgoing_traffic": )(.*)(?=,)' <"$TMP")/1024^3")
Run Code Online (Sandbox Code Playgroud)

顺便说一句,您的tr命令不起作用的一个原因是您删除了反引号。另外,后面的符号<必须是文件名。正确的语法看起来像

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

但如上所述,-z如果您不想要零字节,请不要放置该选项。

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.
Run Code Online (Sandbox Code Playgroud)

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

bash$ echo hello | tr '\n' '\0' | xxd
00000000: 6865 6c6c 6f00                           hello.
Run Code Online (Sandbox Code Playgroud)

and

bc <<<"one"
Run Code Online (Sandbox Code Playgroud)

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

bc <"two"
Run Code Online (Sandbox Code Playgroud)

is equivalent to

echo 2/3 | bc
Run Code Online (Sandbox Code Playgroud)

or

echo 2/3 > file
bc <file
rm file
Run Code Online (Sandbox Code Playgroud)

or

cat <<here >file
2/3
here
bc <file
rm file
Run Code Online (Sandbox Code Playgroud)

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.