$ FILE="$(mktemp)"
$ printf "a\0\n" > "$FILE"
$ od -tx1z "$FILE"
0000000 61 00 0a >a..<
0000003到目前一切尚好。
我将上面的内容包装成bash脚本。
#! /bin/bash
cmd=("$@")
FILE="$(mktemp)"
eval "${cmd[@]}" > "$FILE"
od -tx1z "$FILE"但
$ script printf 'a\0\n'
0000000 61 30 6e >a0n<
0000003为什么输出将\0更改为文字字符串?我怎样才能防止这种情况发生呢?
在这篇文章中并不是很重要:我的问题来自于我试图将一些命令包装到bash脚本中,所以防止命令展开移除NUL.:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"发布于 2018-11-20 17:45:37
为什么输出将
\0更改为文字字符串?我怎样才能防止这种情况发生呢?
因为您使用了eval,它添加了另一个级别的shell处理。eval运行命令printf a\0\n,其中反斜杠转义零和n,并将反斜杠移除。
您可以很好地防止这种情况,而不是使用eval。只要使用"$@" > "$FILE",就可以运行作为脚本参数给出的命令。尽管在这种情况下,您不能像使用eval那样使用重定向或其他shell语法。或者,您可以重新设计整个过程,这样就不需要将命令作为参数传递。
我试图将一些命令包装到bash脚本中,以防止命令扩展删除NUL: S="$(uuencode -m "$FILE“/dev/stdout)”。
这是个问题吗?uuencode -m不应该产生任何NUL字节。正好相反,因为它将二进制数据编码为文本。
最后一个脚本编写一个a、一个NUL和一个换行符到$FILE,并将同样的代码传递给od,后者打印出这些、0000000 61 00 0a或类似的十六进制表示形式。
发布于 2018-11-21 00:18:04
您可以输出NUL到stdout、stderr或从stdin接收它。任何“内部”捕获以及(几乎)任何NUL的使用都是一个问题。
你可以发射NUL到stdout:
$ printf 'a\0b' | sed -n l
a\000b$或者:
$ printf 'a\0b' | cat -A
a^@b还有一个文件:
$ printf 'a\0b' >outfile而且也适用于脚本中的。
第一个脚本的问题是它使用的是eval:
$ cmd=(printf 'a\0b\n')
$ echo "${cmd[@]}"
printf a\0b\n
$ eval echo "${cmd[@]}"
printf a0bn在第二个循环tru中,删除了shell行解析反斜杠。只是不要使用eval:
$ "${cmd[@]}"| sed -n l
a\000b$这证明了(内置的) printf和stdout都能够使用NULs。
但这是失败的:
$ printf '%s\n' "$(printf 'a\0b')" | cat -A
bash: warning: command substitution: ignored null byte in input
ab$甚至(在bash 4.4+中)都有警告消息。
简而言之,shell (大多数shell)在内部使用C-字符串,C-字符串以第一个NUL结尾。在“命令扩展”中,一些炮弹在第一个核处被切割。
$ ksh -c 'echo $(printf "a\0b\n")|sed -n l' # also yash
a$有些人去掉了
$ bash -c 'echo $(printf "a\0b\n")|sed -n l'
ab$有些人甚至把空位改成了空位:
$ zsh -c 'echo $(printf "a\0b\n")|sed -n l'
a b$对于变量的赋值也会出现类似的问题。
是的,您链接到的答案使用uuencode对文件内容进行编码(并解码)。
一个更简单的方法似乎是使用xxd (它可以反转八进制转储):
FILE="$(mktemp)"
printf "a\0b\n" > "$FILE"
S=$(xxd -p "$FILE")
xxd -r -p <(printf '%s' "$S") | xxd -p
rm "$FILE"https://unix.stackexchange.com/questions/483015
复制相似问题