在 Makefile 中,我运行一个 shell 命令,我想将一个 NULL 字节作为参数传递。以下尝试失败:
echo $(shell /bin/echo -n $$'\x00' | ruby -e "puts STDIN.read.inspect")
它生成:
echo "$\\x00"
相反,我期望:
echo "\u0000"
如何正确转义这样的 NULL 字节?
echo
默认情况下禁用反斜杠转义的解释。您需要提供-e
启用它的选项。
$ echo -ne "\x00" | ruby -e "puts STDIN.read.inspect"
"\u0000"
由于 execve(2) 语义,不可能将包含空字节的字符串作为参数传递。每个参数字符串都以空字节结尾,因此无法区分包含的空字节和字符串的结尾。
的这些用途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
NUL
在 bash 中用作参数您不能$'\0'
将其用作参数,将其存储为变量或使用命令替换$(printf '\0')
,因为bash
(以及大多数 shell?)使用以空值结尾的 C 字符串。前面的前导字符串NUL
被解释为字符串,而尾随字符串被丢弃。
您只能使用管道输入 -printf '\0' | cat -v
或让生成的程序使用文件进行输入。
大多数使用行字符串NUL
(xargs
, cut
, ...)进行输入的程序通常都有一个-z
标志。这主要用于处理路径时,因为字符可能包含任何字符 EXCEPT NUL
。
程序喜欢find
并git ls-files
支持输出这种格式,通常以 a-print0
或-0
标志的形式。
sed
, tr
,等程序bash
。人。使用特殊的转义字符,如\0
, \x0
,\x00
来生成NUL
字节。
OP 最初似乎想知道如何使用delimiter cut
。NUL
问题通常是使用 分隔某些内容\n
,其中\n
是值的有效部分,而不是行分隔符(通常在路径中)。
假设您有这样一种情况,您将文件分组,每个文件由一个NUL
字符分隔,组由\n
.
# Temporary mock output with NUL columns and newline rows
printf 'foo\0bar\nbar\0\nFOO\0BAR\0\n' > /tmp/$$.output
一种解决方法是通过组合来获得创意sed
,awk
或者tr
将输出按摩到适合我们输入/命令的东西。
#!/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
如果其他人来这里寻找如何通过 ruby 反引号中的 shell 命令转义 null:
irb(main):024:0> `curl --silent http://some-website-or-stream.com | sed 's/\\x0//g' 1>&2`
=> ""