无法删除/移动文件名中带有特殊字符的文件

kar*_*laa 17 filesystem files encoding filename

正如您在下面看到的,文件具有不常见的字符。

文件管理器截图

在终端或 Dolphin 中删除它们会返回错误:

无此文件或目录

ls -la在目录上运行给了我这个输出:

-rw-rw-r--  1 aalap aalap      0 Nov 14 01:05 ??
-rw-rw-r--  1 aalap aalap      0 Nov 14 01:05 ?2?.?????!?Gb????[?F?
-rw-rw-r--  1 aalap aalap      0 Nov 14 01:05 ??3]d???:????????1????G?p??????????d?????-??
-rw-rw-r--  1 aalap aalap      0 Nov 14 01:05 3l??#g?w????O?JKB7?co???H??bT?NA???S???X?I?A?qC??M?I???
-rw-rw-r--  1 aalap aalap      0 Nov 14 01:05 ??8??-?@,?Zp?[?bI????7^?ñ[????z?O??????eE??+??,OF??h
Run Code Online (Sandbox Code Playgroud)

我在fsck另一个操作系统的分区上运行了一个命令,但它没有改变任何东西。

如何删除这些文件?

Mal*_*ppa 35

一个简单的方法是通过它们的 inode 删除这些文件。:)

使用ls -li目录与常见的字符显示每个文件的inode编号,例如,

$ ls -li
total 0
133370 -rw-r--r-- 1 malte malte 0 Dec 30 19:00 ?2?.?????!?Gb????[?F?
132584 -rw-r--r-- 1 malte malte 0 Dec 30 18:59 ??3]d???:????????1????G?p??????????d?????-??
Run Code Online (Sandbox Code Playgroud)

接下来,使用该find实用程序按名称删除相应的文件,使用语法find <somepath> -inum <inode_number> -exec rm -i {} \;,如下例所示:

$ find . -inum 133370 -exec rm -i {} \;
rm: remove regular empty file ‘./?2?.?????!?Gb????[?F?’? y
$ ls -li
total 0
132584 -rw-r--r-- 1 malte malte 0 Dec 30 18:59 ??3]d???:????????1????G?p??????????d?????-??
Run Code Online (Sandbox Code Playgroud)

-i选项rm是不是真的有必要,我只是说这让你从你并不想删除意外删除的文件。:) 它会rm要求您确认要删除的每个文件。

如果你想通过它们的 inode 删除多个文件,你可以使用-o(mean or ) 语法find

$ find .  \( -inum 133370 -o -inum 132584 \) -exec rm -i {} \;
rm: remove regular empty file ‘./?2?.?????!?Gb????[?F?’? y
rm: remove regular empty file ‘./??3]d???:????????1????G?p??????????d?????-??’? y
Run Code Online (Sandbox Code Playgroud)

您可以通过使用更多-o -inum <inode_number>表达式扩展括号中的表达式来添加更多 inode 编号。

  • `rm -ri .` 怎么样? (4认同)
  • @karjedavpalaa (1) `-inum` 告诉 `find` 通过它们的 inode 编号查找文件。(2) `{}` 匹配 `grep` 找到的文件。(3) \ 转义`;` 符号,该符号终止传递给`find` 的`-exec` 选项的命令。(4) 我编辑了我的答案以解释如何一次性删除多个文件。 (3认同)
  • 不过,@BrentBaccala `rm -ri .` 不会通过 inode 删除文件。它会简单地遍历整个工作目录并询问每个文件是否要删除它-并且您必须非常注意它所请求的文件,以免意外删除不需要的文件。我当然不想将此命令用于我的主目录 - 它包含大量文件。;) (2认同)

zwo*_*wol 13

重要的是要了解这不是fsck有助于解决的“文件系统损坏” 。就文件系统而言,文件名可以是任何字节序列,只要没有单个字节具有值 0x00(ASCII NUL,C 字符串结束标记)或 0x2F(/目录分隔符)。(如果文件名以某种方式在其中嵌入了 00 或 2F 字节,fsck则应解决该问题。)

相反,您拥有的是应用程序软件(Dolphin,ls)认为包含在您的“语言环境”中无法显示的字符的文件名,因此它用占位符字符替换它们。您也无法键入这些字符,因此操作文件更加困难,但只要您不键入或复制和粘贴名称就可以操作。例如,如果您直接从 Dolphin 中删除或重命名问题文件,那应该可以正常工作(我什至会说,如果它不起作用,那是 Dolphin 中的错误)。

如果您需要在 shell 中对它们做一些事情(例如,如果它们root由 GUI 程序拥有,因此不能被 GUI 程序修改),您可以使用“glob”模式间接命名它们,这些模式将被扩展为正确的序列(s) 个字节并传递。

现在,当然,您不会因为 glob 模式匹配太多而意外删除内容,所以我的建议是使用 Perlrename实用程序将每个文件名转换为其十六进制编码:

$ rename '$_ = unpack("H*", $_)' *
Run Code Online (Sandbox Code Playgroud)

这不会破坏任何信息 - 无论是文件本身,也不是文件名在被破坏之前最初可能编码的任何含义。它可以针对特定文件撤消,例如

$ rename '$_ = pack("H*", $_)' 696d706f7274616e742e646f63
Run Code Online (Sandbox Code Playgroud)

注意:有两个程序名为rename,来自不同的来源;上述命令仅适用于源自 Perl 的命令。在 Ubuntu 中,您想要的是“重命名”包中的那个,而不是“util-linux”包中的那个。 rename -h会区分:这就是你想要的......

$ rename -h
Usage:
    rename [ -h|-m|-V ] [ -v ] [ -n ] [ -f ] [ -e|-E perlexpr]*|perlexpr
    [ files ]
# ...
Run Code Online (Sandbox Code Playgroud)

……这不是你想要的……

$ rename -h

Usage:
 rename [options] <expression> <replacement> <file>...
# ...
Run Code Online (Sandbox Code Playgroud)

要寻找的关键是“perlexpr”。您可能有一个旧版本的 Perl 重命名,它不能理解上述所有选项,但我展示的命令应该仍然有效。

编辑:在 14.04 .5 下,包含的 perl 脚本rename不支持 -h 开关。你可以通过检查它的手册页来确认你有正确的,man rename在这种情况下,顶行将包含:

RENAME(1) Perl 程序员参考指南 RENAME(1)