我已成功编写以下功能:
function print0(){
stdin=$(cat);
echo "$stdin" | awk 'BEGIN {ORS="\000";}; { print $0}';
}
在-print0
命令中用作find
参数,但基本上用于将其输出传递给此函数的任何命令。它对xargs -0
很有用。然后我意识到这个函数的反面也是有用的。我试过以下:
function read0(){
stdin=$(cat);
echo "$stdin" | awk 'BEGIN {RS="\000"; ORS="\n";}; {print $0}';
# EQUIVALENTS:
# echo "$stdin" | perl -nle '@a=join("\n", split(/\000/, $_)); print "@a"'
# echo "$stdin" | perl -nle '$\="\n"; @a=split(/\000/, $_); foreach (@a){print $_;}'
}
但它不起作用,有趣的是,当我尝试命令(awk或perl)时,它就像一个魅力:
# WORKING
ls | print0 | awk 'BEGIN {RS="\000"; ORS="\n";}; {print $0}'
ls | print0 | perl -nle '@a=join("\n", split(/\000/, $_)); print "@a"'
ls | print0 | perl -nle '$\="\n"; @a=split(/\000/, $_); foreach (@a){print $_;}'
# DOES NOT WORKING
ls | print0 | read0
我做错了什么?我假设通过以下命令处理空字符有问题:stdin=$(cat);
修改 谢谢大家,结论是bash变量不能保存null值。 PS:提到的命令就是一个例子我知道将空值转换为换行符,反之亦然没有理性的原因。
答案 0 :(得分:2)
我想说你的实现可以简化为
function print0 { tr '\n' '\0'; }
function read0 { tr '\0' '\n'; }
可以根据需要使用。
但是,它没有增加任何价值;您只需从换行记录切换到NUL
分隔的记录,反之亦然,而find ... -print0
可以处理多行文件名。你的想法并没有解决这个问题。
您的问题的实际观点 - 如何在bash中处理嵌入NUL
字符的字符串 - 已在SO assign string containing null-character (\0) to a variable in bash上进行了讨论。最重要的是,你必须逃脱它们。除此之外,zsh支持嵌入的NUL
字符,但显然没有其他shell。
NUL
shell内置read
字符的处理related discussion on bug-bash,您可能会感兴趣。
答案 1 :(得分:1)
正如其他答案/评论所提到的,您不能在bash字符串变量中放置空字符。但是,如果您可以摆脱变量并只处理管道/流中的数据,那么您可以通过以下方式传递空字符:
function print0() { awk 'BEGIN {ORS="\000";}; {print $0}'; } function read0() { awk 'BEGIN {RS="\000"; ORS="\n";}; {print $0}'; }
ubuntu@ubuntu:~/dir$ ls -1 file one file_two ubuntu@ubuntu:~/dir$ ls | print0 | read0 file one file_two ubuntu@ubuntu:~/dir$
以这种方式使用ls
也很危险,因为它不适用于包含换行符的文件名。据我所知,find
是 以编程方式获取目录中文件列表的方式,当文件名中出现奇数字符时。
<强>更新强>
这是另一种以编程方式获取目录中文件列表的方法,当奇数字符出现在文件名中时,不使用find
(或有缺陷的ls
)。我们可以使用* glob将目录中所有文件的列表放入bash数组中。然后我们打印出数组的每个成员,使用/ dev / zero的1个字符作为分隔符:
#!/bin/bash
shopt -s nullglob
shopt -s dotglob # display .files as well
dirarray=( * )
for ((i = 0 ; i < ${#dirarray[@]}; i++)); do
[ "$i" != "0" ] && head -c1 /dev/zero
printf "${dirarray[$i]}"
done