首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何通过脚本将NUL正确地输出到文件?

如何通过脚本将NUL正确地输出到文件?
EN

Unix & Linux用户
提问于 2018-11-20 17:32:30
回答 2查看 284关注 0票数 1
代码语言:javascript
复制
$ FILE="$(mktemp)"
$ printf "a\0\n" > "$FILE"
$ od -tx1z "$FILE"
0000000 61 00 0a                                         >a..<
0000003

到目前一切尚好。

我将上面的内容包装成bash脚本。

代码语言:javascript
复制
#! /bin/bash

cmd=("$@")
FILE="$(mktemp)"
eval "${cmd[@]}" > "$FILE"
od -tx1z "$FILE"

代码语言:javascript
复制
$ script printf 'a\0\n' 
0000000 61 30 6e                                         >a0n<
0000003

为什么输出将\0更改为文字字符串?我怎样才能防止这种情况发生呢?

在这篇文章中并不是很重要:我的问题来自于我试图将一些命令包装到bash脚本中,所以防止命令展开移除NUL.

代码语言:javascript
复制
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
EN

回答 2

Unix & Linux用户

回答已采纳

发布于 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或类似的十六进制表示形式。

票数 1
EN

Unix & Linux用户

发布于 2018-11-21 00:18:04

您可以输出NUL到stdout、stderr或从stdin接收它。任何“内部”捕获以及(几乎)任何NUL的使用都是一个问题。

你可以发射NUL到stdout:

代码语言:javascript
复制
$ printf 'a\0b' | sed -n l
a\000b$

或者:

代码语言:javascript
复制
$ printf 'a\0b' | cat -A
a^@b

还有一个文件:

代码语言:javascript
复制
$ printf 'a\0b' >outfile

而且也适用于脚本中的

eval

第一个脚本的问题是它使用的是eval

代码语言:javascript
复制
$ cmd=(printf 'a\0b\n')
$ echo "${cmd[@]}"
printf a\0b\n

$ eval echo "${cmd[@]}"
printf a0bn

在第二个循环tru中,删除了shell行解析反斜杠。只是不要使用eval:

代码语言:javascript
复制
$ "${cmd[@]}"| sed -n l
a\000b$

展开

这证明了(内置的) printfstdout都能够使用NULs。

但这是失败的:

代码语言:javascript
复制
$ 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结尾。在“命令扩展”中,一些炮弹在第一个核处被切割。

代码语言:javascript
复制
$ ksh -c 'echo $(printf "a\0b\n")|sed -n l'    # also yash
a$

有些人去掉了

代码语言:javascript
复制
$ bash -c 'echo $(printf "a\0b\n")|sed -n l'
ab$

有些人甚至把空位改成了空位:

代码语言:javascript
复制
$ zsh -c 'echo $(printf "a\0b\n")|sed -n l'
a b$

对于变量的赋值也会出现类似的问题。

编码

是的,您链接到的答案使用uuencode对文件内容进行编码(并解码)。

一个更简单的方法似乎是使用xxd (它可以反转八进制转储):

代码语言:javascript
复制
FILE="$(mktemp)"
printf "a\0b\n" > "$FILE"
S=$(xxd -p "$FILE")
xxd -r -p <(printf '%s' "$S") | xxd -p
rm "$FILE"
票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/483015

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档