识别文件名中包含非ASCII或不可打印字符的文件


24

在具有大约700,000个文件的80GB目录大小中,某些文件名中包含非英语字符。除了费力地浏览文件列表之外,还有:

  • 列出或标识这些文件名的简便方法?
  • 一种生成可打印的非英语字符的方法-那些不在可打印范围内的字符man ascii(以便我可以测试这些文件是否已被识别)?

Answers:


32

假设“外国”的意思是“不是ASCII字符”,那么您可以使用find一种模式来查找名称中没有可打印ASCII字符的所有文件:

LC_ALL=C find . -name '*[! -~]*'

(空格是http://www.asciitable.com/上列出的第一个可打印字符,~是最后一个。)

的提示LC_ALL=C是必需的(实际上是LC_CTYPE=CLC_COLLATE=C),否则字符范围将被错误地解释。另请参见手册页glob(7)。由于LC_ALL=C导致find将字符串解释为ASCII,因此它将打印多字节字符(例如π)作为问号。要解决此问题,请通过管道传输到某个程序(例如cat)或重定向到文件。

除了指定字符范围外,[:print:]还可用于选择“可打印字符”。确保设置C语言环境,否则您将获得(似乎)任意行为。

例:

$ touch $(printf '\u03c0') "$(printf 'x\ty')"
$ ls -F
dir/  foo  foo.c  xrestop-0.4/  xrestop-0.4.tar.gz  π
$ find -name '*[! -~]*'       # this is broken (LC_COLLATE=en_US.UTF-8)
./x?y
./dir
./π
... (a lot more)
./foo.c
$ LC_ALL=C find . -name '*[! -~]*'
./x?y
./??
$ LC_ALL=C find . -name '*[! -~]*' | cat
./x y
./π
$ LC_ALL=C find . -name '*[![:print:]]*' | cat
./x y
./π

1
请注意,您拥有的文件名使用的外部字符集与UTF-8或ASCII不兼容。在这种情况下,您可能会看到问号而不是字符。
Lekensteyn 2014年

1
+1,但我会使用LC_ALL=C而不是,LC_COLLATE=C因为在没有设置的情况下将LC_COLLATE设置为C LC_CTYPE并确保即使LC_ALL变量在环境中也可以正常工作并没有多大意义。
斯特凡Chazelas

如果SPC打印的,那么怎么样TAB以及LF它们也通常在文本文件中发现了什么?
斯特凡Chazelas

1
谢谢-找到了六个文件,它们有长连字符,短连字符和单引号的变体。这些都是源于MS Word。LC_ALL和LC_COLLATE之间列出的文件没有差异。LC_COLLATE正确显示非ASCII字符,而LC_ALL显示??? 代替。很好的答案!
嫌疑犯2014年

1
@suspectus我根据Stephane的建议通过答案进行了更新。对于LC_COLLATELC_CTYPE,另请参见find(1)联机帮助页。
Lekensteyn 2014年

6

如果使用转换每个文件名tr -d '[\200-\377]'并将其与原始名称进行比较,则任何带有特殊字符的文件名都将不同。

(以上假设您的意思是非ASCII与外部语言)


2
在大多数实现中[,这也删除了。]tr
斯特凡Chazelas

是的-它确实删除[]我的系统上。
嫌疑犯2014年

+1-解决方案确实找到了所有(六个)具有非ASCII符号的文件名(除了[和之外])。谢谢。
嫌疑犯2014年

3

您可以用来tr从文件名中删除任何外来字符,并将结果与​​原始文件名进行比较,以查看其是否包含外来字符。

find . -type f > filenames
while read filename; do
      stripped="$(printf '%s\n' "$filename" | tr -d -C '[[:alnum:]][[:space:]][[:punct:]]')"
      test "$filename" = "$stripped" || printf '%s\n' "$filename"; 
done < filenames

4
那是对我的答案的一个很好的扩展,但它太简单了,文件名中可以​​包含换行符,然后您的脚本将无法工作
Timo 2014年

1
如果要对find输出进行后处理,请使用NUL终止的输出/输入,如此答案所示。
Lekensteyn 2014年

0

可接受的答案会有所帮助,但是如果您的文件名已经采用LANG/中指定的编码LC_CTYPE,则最好这样做:

LC_COLLATE=C find . -name '*[! -~]*'

字符类受的影响LC_CTYPE,但是上述命令不使用字符类,仅使用范围,因此LC_CTYPE仅防止将不寻常的字符替换为问号。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.