cat可以将任何文件复制到stdout; 该文件不需要是文本文件.NUL例如,它可能包括s,而a NUL不能用sh字符串表示.所以这肯定是一个特征cat,即使不是不可能,也很难实现.[注1]
除此之外,你应该能够紧裹read和echo一个内while循环,虽然有一些棘手的问题.(例如,准确地再现不以换行符结尾的非空文件.)
但是,从技术上讲,echo是不多的部分sh比cat是; 就像cat,它是一个可能不存在的实用程序(在非Posix系统上).在实践中,没有echo环境的环境与没有环境的环境差不多cat; 如果你有sh,你有合理的期望找到标准的命令行实用程序.
最小兼容Posix的唯一选择read是-r.但是,如果我们有bash实现read,我们可以逐个字符地复制文件,即使该NUL字符实际上永远不会出现在shell变量中:
while IFS= read -d '' -rn1 char; do
if [ -z "$char" ]; then printf '\0'; else printf '%s' "$char"; fi
done < "$1" > "$2"
Run Code Online (Sandbox Code Playgroud)
例:
$ printf 'foo\0bar\n\nbye' |
> while IFS= read -d '' -rn1 char; do
> if [ -z "$char" ]; then printf '\0'; else printf '%s' "$char"; fi
> done |
> hd
00000000 66 6f 6f 00 62 61 72 0a 0a 62 79 65 |foo.bar..bye|
0000000c
Run Code Online (Sandbox Code Playgroud)
该read调用中的完整选项集经过精心设计,可以解决bash实现中的各种特性:
IFS= 避免从结果中删除尾随空格字符.-n1导致一个字符被读取,直到分隔符.直觉上,-N1更自然,因为-N1忽略了分隔符.但是,read也会NUL从输入中删除字符.由于$char如果下一个字符是a NUL,意图是存储零个字符,我们可以通过使用-n1和设置分隔符来避免这个问题NUL,这是因为分隔符检查是在NUL剥离s 之前完成的.-d ''将行分隔符设置为NUL.往上看.-r避免\在输入流中被解释; 这是该集中唯一与Posix兼容的选项.不言而喻,上述仅仅是理论上的兴趣,或者作为OP的智力测验.在实践中,一个shell脚本应该做的不超过协调的外部公用设施的工作更多,并且符合POSIX标准的实用程序,如存在cat,dd,head并tail应足以满足任何文件复印需求.