我怎样才能摆脱这个不可见的文件?

我怎样才能摆脱这个不可见的文件?

背景

我有一个名为 的文件夹akorg✽。当软件对我的文件路径的文本编码做出错误的假设时,这个 Unicode 字符会让我头疼,所以我想从名称中删除它。

问题

你可能认为这很容易:

$ mv akorg✽ akorg
mv: cannot move ‘akorg✽’ to a subdirectory of itself, ‘akorg/akorg✽’

但是,这很奇怪,它认为名为 的文件夹akorg已经存在。我很确定没有一个:

$ ls -la
total 699K
drwxr-xr-x 15 ak ak   15 Jun 12 17:34 .
drwxr-xr-x 57 ak ak 4.0K Jun 12 17:35 ..
drwxr-xr-x 11 ak ak   21 Jun 12 16:58 akorg✽
drwxr-xr-x  2 ak ak    2 May 28 20:47 Desktop
...

不过,stat另有说法:

$ stat akorg
  File: ‘akorg’
  Size: 21          Blocks: 33         IO Block: 1536   directory
Device: 15h/21d Inode: 292128      Links: 11
...

显然有一个看不见的文件夹挡住了。不管怎样,我会把它删除:

$ rmdir akorg
rmdir: failed to remove ‘akorg’: No such file or directory

好吧,那么。这到底是什么东西?

到目前为止我所知道的

  • 我正在使用稳定发布Linux 上的 ZFS。这是zpool 状态和 zfs 属性
  • statakorg为和都返回相同的 inode akorg✽。按该索引节点搜索仅返回akorg✽

    $ find . -maxdepth 1 -inum 292128
    ./akorg✽
    
  • 更多不适用于“不可见”文件夹的操作:

    $ rm akorg
    rm: cannot remove ‘akorg’: Is a directory
    $ unlink akorg
    unlink: cannot unlink ‘akorg’: Is a directory
    $ mv akorg akorg_temp
    mv: cannot move ‘akorg’ to ‘akorg_temp’: No such file or directory
    
  • 我在 Bash 4.2.45 和 zsh 5.0.0 中得到相同的结果。在这两种情况下,制表符补全ak仅返回akorg✽/
  • 斯特雷斯我最初的重命名尝试确认我输入的名称正确,并且该尝试因预先存在的名为 的文件夹而受阻akorg
  • 对更明确的重命名尝试的回应令人费解和可怕:

    $ mv --verbose --no-target-directory --no-clobber akorg✽ akorg
    removed ‘akorg✽’
    

    我不明白为什么它声称已经删除了akorg✽,或者为什么它会尝试。幸运的是,lsstat akorg akorg✽透露实际上什么都没有消失。这是斯特雷斯

  • 为了排除编码怪异的原因,我暂时给出了akorg✽一个中间名称:

    $ mv --verbose --no-target-directory --no-clobber akorg✽ bananas
    ‘akorg✽’ -> ‘bananas’
    

    正如预期的那样,

    $ ls -la
    total 715K
    drwxr-xr-x 16 ak ak   16 Jun 13 15:11 .
    drwxr-xr-x 57 ak ak 4.0K Jun 13 14:03 ..
    drwxr-xr-x 11 ak ak   21 Jun 12 16:58 bananas
    drwxr-xr-x  2 ak ak    2 May 28 20:47 Desktop
    ...
    

    但“不可见”文件夹仍然存在:

    $ stat bananas akorg
      File: ‘bananas’
      Size: 21          Blocks: 33         IO Block: 1536   directory
    Device: 15h/21d Inode: 292128      Links: 11
    ...
      File: ‘akorg’
      Size: 21          Blocks: 33         IO Block: 1536   directory
    Device: 15h/21d Inode: 292128      Links: 11
    ...
    

    mv当我尝试使用该名称时,仍然表现得很奇怪akorg

    $ mv --verbose --no-target-directory --no-clobber bananas akorg
    removed ‘bananas’
    

答案1

当您使用 zsh 时,我建议使用制表符补全或 shell 通配符(在删除之前始终使用 echo/ls )。如果这些不起作用,您有以下几种选择:

通过十六进制转储检查您的文件名并用于$'...'输入它

% touch akorg✽   
% ls | grep akorg | hexdump -C
00000000  61 6b 6f 72 67 e2 9c bd  0a                       |akorg....|
00000009
% ls $'akorg\xe2\x9c\xbd'  
akorg✽
% rm $'akorg\xe2\x9c\xbd'
% ls
% 

请注意,上面的最后一个0a是输入末尾的换行符,因此我们不希望它出现在我们的名称中。

用于ls -i获取inode号并用于find删除它

% touch akorg✽
% ls -i
6128574 akorg✽
% find . -inum 6128574
akorg✽
% find . -inum 6128574 -delete
% ls
% 

您也可以find按名称(无论哪种方式,请先打印!)

用于ls -b获取转义名称并输入它$'...'(这适用于非打印字符,但似乎不会影响您的 unicode 字符,因此仅供其他人参考)。

% ls
foo?bar
% ls -b         
foo\rbar
% rm foo$'\r'bar
% ls
% 

答案2

这很奇怪。(这个“答案”一开始是一条评论;),后来变得有点长。)

看看它strace看起来没有隐藏字符或类似的东西,否则我怀疑你会在例如中看到它(这应该会导致-1 ENOENT而不是0如果一切正常的话):

stat("akorg", {st_mode=S_IFDIR|0755, st_size=21, ...}) = 0

正如您在以下内容中所做的那样:

lstat("akorg\342\234\275", {st_mode=S_IFDIR|0755, st_size=21, ...}) = 0

遇到一个邮件交换,其中一个人拥有相反的问题ls列出文件,但是stat给出ENOENT——尽管那是在 FreeBSD 上。

我不太了解zfs,但是否可能某些同步、快照等失败并留下损坏的文件表?您是否创建/拥有一个名为akorg您在尝试之前删除的目录mv

不知道您是否可以通过以下方式获取一些错误描述:

# zpool status -v

要尝试的一件事是检查反向 inode 查找(可以选择添加另一个d)并检查path

# zdb -dddd <pool-name> <inode>

在名为的文件夹中baz

# zdb -dddd qqq 31
Object  lvl   iblk   dblk  dsize  lsize   %full  type
    31    1    16K    512     1K    512  100.00  ZFS directory
                                    264   bonus  ZFS znode
dnode flags: USED_BYTES USERUSED_ACCOUNTED 
dnode maxblkid: 0
path    /baz
uid     1000
gid     1000
atime   Fri Jun 14 12:39:46 2013
mtime   Fri Jun 14 11:55:33 2013
ctime   Fri Jun 14 11:55:33 2013
crtime  Fri Jun 14 11:55:33 2013
gen 1510
mode    40775
size    2
parent  3
links   2
xattr   0
rdev    0x0000000000000000
microzap: 512 bytes, 0 entries

在名为 的目录中foo包含多个子目录,其中包括一个名为 的子目录akorg✽

Object  lvl   iblk   dblk  dsize  lsize   %full  type
    16    1    16K    512     1K    512  100.00  ZFS directory
                                    264   bonus  ZFS znode
dnode flags: USED_BYTES USERUSED_ACCOUNTED 
dnode maxblkid: 0
path    /foo
uid     1000
gid     1000
atime   Fri Jun 14 13:10:38 2013
mtime   Fri Jun 14 12:13:18 2013
ctime   Fri Jun 14 12:13:18 2013
crtime  Fri Jun 14 11:41:53 2013
gen 1482
mode    40775
size    6
parent  3
links   6
xattr   0
rdev    0x0000000000000000
microzap: 512 bytes, 4 entries

    foo1 = 15 (type: Directory)
    foo2 = 18 (type: Directory)
    foo = 19 (type: Directory)
    akorg✽ = 30 (type: Directory)

您对各种名称 mod 的设置zfs get all storage/home-ak-annex看起来也很正常(据我所知)以及通过阅读的其他属性ZFS 属性:

storage/home-ak-annex  utf8only              off                    -
storage/home-ak-annex  normalization         none                   -
storage/home-ak-annex  casesensitivity       sensitive              -

如果您zfs自己构建,则可以启用调试./configure --enable-debug并使用上述内容-vvvv,包括-bbbb等。

最后你可以打开一个新问题在 git 上。

答案3

我猜你没有一个不可见的目录,而是错误stat打印了 unicode 字符,以便文件名好像 akorg当出现在屏幕上时。

两种可能的解决方案:

  1. 使用具有制表符补全功能的 shell(zsh 或 bash)。根据提示执行:rm -rf akorg<tab>。 Zsh 至少会完成文件名,并根据需要转义 shell 特殊字符。

  2. 单行,有点冒险:rm -rf akorg?

你可以手动执行#2,例如:ls -1 > filenames。在名为“filenames”的文件上使用某些文本编辑器删除除有问题的目录之外的所有行。rm -rf向该行添加前缀。退出编辑器。作为 shell 脚本执行:sh filenames

相关内容