3

在 Makefile 中,我运行一个 shell 命令,我想将一个 NULL 字节作为参数传递。以下尝试失败:

echo $(shell /bin/echo -n $$'\x00' | ruby -e "puts STDIN.read.inspect")

它生成:

echo "$\\x00"

相反,我期望:

echo "\u0000"

如何正确转义这样的 NULL 字节?

4

5 回答 5

9

echo默认情况下禁用反斜杠转义的解释。您需要提供-e启用它的选项。

$ echo -ne "\x00" | ruby -e "puts STDIN.read.inspect"
"\u0000"
于 2013-06-14T12:30:37.717 回答
7

由于 execve(2) 语义,不可能将包含空字节的字符串作为参数传递。每个参数字符串都以空字节结尾,因此无法区分包含的空字节和字符串的结尾。

于 2013-06-14T12:55:31.993 回答
1

的这些用途echo是完全不可移植的。使用printf,除了最简单的字符串之外,它更容易用于任何东西,并且更便携。

$ cat makefile
all:
        printf '\0' > foo.out
        od -a foo.out

$ make
printf '\0' > foo.out
od -a foo.out
0000000 nul
0000001
于 2013-06-14T12:06:27.883 回答
1

您不能NUL在 bash 中用作参数

您不能$'\0'将其用作参数,将其存储为变量或使用命令替换$(printf '\0'),因为bash(以及大多数 shell?)使用以空值结尾的 C 字符串。前面的前导字符串NUL被解释为字符串,而尾随字符串被丢弃。

您只能使用管道输入 -printf '\0' | cat -v或让生成的程序使用文件进行输入。

使用另一种输入方式

大多数使用行字符串NULxargs, cut, ...)进行输入的程序通常都有一个-z标志。这主要用于处理路径时,因为字符可能包含任何字符 EXCEPT NUL

程序喜欢findgit ls-files支持输出这种格式,通常以 a-print0-0标志的形式。

sed, tr,等程序bash。人。使用特殊的转义字符,如\0, \x0,\x00来生成NUL字节。

按摩输入

OP 最初似乎想知道如何使用delimiter cutNUL问题通常是使用 分隔某些内容\n,其中\n是值的有效部分,而不是行分隔符(通常在路径中)。

假设您有这样一种情况,您将文件分组,每个文件由一个NUL字符分隔,组由\n.

# Temporary mock output with NUL columns and newline rows
printf 'foo\0bar\nbar\0\nFOO\0BAR\0\n' > /tmp/$$.output

一种解决方法是通过组合来获得创意sedawk或者tr将输出按摩到适合我们输入/命令的东西。

我们的.sed

#!/usr/bin/sed -nf

# beginning
:x 
# match \0\n
/\x0$/ {
 # Change \0\n to \n
 s|\x0$|\n|g
 # print
 p
 # delete
 d
}
# match \n with no leading \0
/[^\x0]$/ {
 # change \0 to \1
 s|\x0|\x1|g
 # read next line
 N
 # branch to beginning
 bx
}

在这种情况下,我们映射:

  • \0\n=>\n
  • \0后面没有\n=>\1
    虽然文件名中的有效字符,但它不太可能造成问题。
# Change NUL to another unlikely to be used control character
sed -f our.sed /tmp/$$.output |\
  cut -d $'\x1' -f 2

输出

bar
BAR
于 2021-12-19T01:45:37.970 回答
0

如果其他人来这里寻找如何通过 ruby​​ 反引号中的 shell 命令转义 null:

irb(main):024:0> `curl --silent http://some-website-or-stream.com | sed 's/\\x0//g' 1>&2`
=> ""
于 2017-06-07T14:09:39.240 回答