我有一些包含不可打印字符的旧迁移文件。 我想find这样的名字的所有文件,并从系统中完全删除它们。
例:
ls -l -rwxrwxr-x 1 cws cws 0 Dec 28 2011 ??"?? ls -lb -rwxrwxr-x 1 cws cws 0 Dec 28 2011 a211"206351
我想find所有这样的文件。
在所有文件中使用grep和sed查找和replacestring
简单的shell linux C实现,用freopenredirect标准输出
使用 – 和 – 作为选项设置位置参数时设置的区别
什么是以下“top”命令语法的简要说明:top -p`pgrep process-name | tr“\ n”“,”| sed's /,$ //'`
Bash:找出哪些行在两个文件之间没有改变
将目录中的所有文件复制到Linux中的本地子目录中
非ASCII字符
ASCII字符代码范围从十六进制的0x00到0x7F 。 因此,任何代码大于0x7F字符都是非ASCII字符。 这包括UTF-8中的大部分字符(ASCII码本质上是UTF-8的一个子集)。 例如,日本人的性格
あ
在UTF-8中以十六进制编码
E3 81 82
从版本8.0(2002)开始, UTF-8已经成为默认的字符编码,包括从版本8.0(2002)开始的Red Hat Linux,从版本9.1(2004)开始的SuSE Linux以及从5.04(2005)开始的Ubuntu Linux 。
ASCII控制字符
在ASCII代码中, 0x00到0x1F和0x7F代表控制字符,如ESC ( 0x1B )。 这些控制字符本来并不打算是可打印的,即使它们中的一些像换行符0x0A可以被解释和显示。
在我的系统上, ls显示所有的控制字符? 默认情况下,除非我传递--show-control-chars选项。 我猜你想删除的文件包含ASCII控制字符,而不是非ASCII字符。 这是一个重要的区别:如果删除包含非ASCII字符的文件名,则可能会吹走刚刚以另一种语言命名的合法文件。
字符代码的正则表达式
POSIX
POSIX提供了一个非常方便的字符类集合来处理这些类型的字符(感谢bashophil指出了这一点):
[:cntrl:] Control characters [:graph:] Graphic printable characters (same as [:print:] minus the space character) [:print:] Printable characters (same as [:graph:] plus the space character)
PCRE
Perl兼容正则表达式允许使用语法的十六进制字符代码
x00
例如,日语字符あ的PCRE正则表达式就是
xE3x81x82
除了上面列出的POSIX字符类外,PCRE还提供了[:ascii:]字符类,它是[x00-x7F]的简便缩写。
GNU的grep版本支持使用-P标志的PCRE,但BSD grep (例如在Mac OS X上)不支持。 GNU和BSD都不支持PCRE正则表达式。
查找文件
GNU find支持POSIX正则表达式(感谢iscfrc指出纯find解决方案,以避免产生额外的进程)。 以下命令将列出当前目录下包含不可打印控制字符的所有文件名(但不包括目录名称):
find -type f -regextype posix-basic -regex '^.*/[^/]*[[:cntrl:]][^/]*$'
正则表达式有点复杂,因为-regex选项必须匹配整个文件路径,而不仅仅是文件名,因为我假设我们不想用正常名称吹走文件,只是因为它们在目录内包含控制字符的名称。
要删除匹配的文件,只需传递-delete选项, 在所有其他选项 (这是关键的;传递 – 删除作为第一个选项将会吹走当前目录中的所有内容)之后找到:
find -type f -regextype posix-basic -regex '^.*/[^/]*[[:cntrl:]][^/]*$' -delete
我强烈建议先运行该命令, 而不要先删除-delete ,这样可以在太迟之前查看要删除的内容。
如果您还传递-print选项,则可以看到命令运行时正在删除的内容:
find -type f -regextype posix-basic -regex '^.*/[^/]*[[:cntrl:]][^/]*$' -print -delete
要删除包含控制字符的任何路径 (文件或目录),正则表达式可以被简化,您可以删除-type选项:
find -regextype posix-basic -regex '.*[[:cntrl:]].*' -print -delete
使用此命令,如果目录名称包含控制字符,即使目录内没有任何文件名,它们都将被删除。
更新:查找非ASCII 和控制字符
它看起来像你的文件包含非ASCII字符和 ASCII控制字符。 事实证明, [:ascii:] 不是 POSIX字符类,而是由PCRE提供的。 我找不到一个POSIX正则表达式来做这件事,所以这是Perl的救援。 我们仍然使用find来遍历我们的目录树,但是我们会将结果传递给Perl进行处理。
为了确保我们可以处理包含换行符的文件名(在这种情况下很可能),我们需要使用-print0参数来find (在GNU和BSD版本上都支持)。 这会将记录与空字符( 0x00 )而不是换行符分开,因为空字符是在Linux上不能处于有效文件名的唯一字符。 我们需要将相应的标志-0传递给我们的Perl代码,以便知道记录是如何分开的。 以下命令将递归地打印当前目录中的每个路径:
find . -print0 | perl -n0e 'print $_,"n"'
请注意,这个命令只产生一个Perl解释器的实例,这对性能有好处。 起始路径参数(在这种情况下,对于CWD )在GNU find是可选的,但在Mac OS X上的BSD find是必需的,所以为了便于携带,我将它包含在内。
现在为我们的正则表达式。 这是一个PCRE正则表达式匹配包含非ASCII或非打印(即控制)字符(或两者)的名称:
[[:^ascii:][:cntrl:]]
以下命令将打印当前目录中与此正则表达式匹配的所有路径 (目录或文件):
find . -print0 | perl -n0e 'chomp; print $_,"n" if /[[:^ascii:][:cntrl:]]/'
chomp是必须的,因为它从每条路径上chomp了尾随的空字符,否则就会匹配我们的正则表达式。 要删除匹配的文件和目录,我们可以使用以下内容:
find . -print0 | perl -MFile::Path=remove_tree -n0e 'chomp; remove_tree($_,{verbose=>1}) if /[[:^ascii:][:cntrl:]]/'
这也将打印出命令运行时被删除的内容(虽然控制字符被解释,所以输出将不会完全匹配ls的输出)。
到目前为止,您可能已经解决了您的问题,但是对于我的情况来说,这并不适用,因为我使用-regex开关时没有find显示的文件。 所以我使用ls开发了这个解决方法。 希望对某人有用。
基本上,对我来说是这样的:
ls -1 -R -i | grep -a "[^A-Za-z0-9_.':@ /-]" | while read f; do inode=$(echo "$f" | cut -d ' ' -f 1); find -inum "$inode" -delete; done
打破它的部分:
ls -1 -R -i
这将在当前目录下递归地( -R )列出( ls )文件,每行一个文件( -1 ),以其inode号码( -i )为每个文件加上前缀。 结果将被传送到grep 。
grep -a "[^A-Za-z0-9_.':@ /-]"
将每个输入作为文本( -a )进行筛选,即使它最终是二进制文件。 如果它包含一个不同于列表中指定的字符,则grep将让一行通过。 结果将被传送到while 。
while read f do inode=$(echo "$f" | cut -d ' ' -f 1) find -inum "$inode" -delete done
这一次将遍历所有条目,提取inode号码并传递inode find ,然后删除该文件。
你只能用grep打印包含反斜线的行:
ls -lb | grep \\
有可能用grep -P使用PCRE,而不是用find(不幸的是)。 您可以使用exec链接查找与grep。 使用PCRE(perl regex),我们可以使用ascii类,找到任何非ascii的字符。
find . -type f -exec sh -c "echo "{}" | grep -qP '[^[:ascii:]]'" ; -exec rm {} ;
除非第一个返回一个非错误代码,否则以下exec将不会执行。 在这种情况下,这意味着表达式匹配文件名。 我用sh -c因为-exec不喜欢管道。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。