我想按字符过滤文件(为了删除我无法控制生成的无效 xml 字符),但我似乎甚至无法将单个字符从一个文件复制到另一个文件。我printf
以前曾经复制过包括回车符在内的文字部分,但现在它不会将回车符复制为一个,而是复制为一些空长度字符串。我的代码:
infile=$1
outfile=$2
touch $outfile
while IFS= read -r -n1 char
do
# display one character at a time
printf "%s" "$char" >> $outfile
done < "$infile"
diff $infile $outfile
我不介意使用 sed 或 awk,但我必须对允许的字符进行编码。
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
答案1
回车应该不是问题,read
应该可以正常读取。换行符(换行符)是,因为它是read
.你可以使用这个read -d ''
技巧来让它发挥作用。
echo $'\r' | { IFS= read -r -n1 x; echo "$x"|xxd; } # CR
echo $'\n' | { IFS= read -r -n1 x; echo "$x"|xxd; } # LF fails
echo $'\n' | { IFS= read -d '' -r -n1 x; echo "$x"|xxd; } # LF ok
但是,正如他们所说,您可能不想在 shell 中做这样的事情。tr
这正是删除一组固定字符所需的,但至少 GNUtr
适用于字节,而不是字符,因此它对 Unicode 没有多大用处。
我认为这个 Perl 应该可以工作,对于 UTF-8 数据,如果你的区域设置正确设置为 UTF-8:
perl -C -pe 'tr/\x09\x0a\x0d\x20-\x{d7ff}\x{e000}-\x{fffd}\x{10000}-\x{10ffff}//cd' < in > out
但最好测试一下,我不太习惯 Unicode 怪癖。
tr/abc//cd
abc
删除(中未列出的字符tr///
实际上是将字符转换为其他字符,请参见perlop
)。它接受字符列表以及范围,并表示具有十六进制值的字符\xHH
赫赫,以及一个有价值的\x{HHHH}
呵呵呵呵。所以上面接受0x09
, 0x0a
, 0x0d
, 从0x20
到0xd7ff
等的所有内容。
上面的列表直接取自问题中提供的列表。我将把它留给最终用户来评估是否应该更改。