背景
我有一个名为 的文件夹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 属性。
stat
akorg
为和都返回相同的 inodeakorg✽
。按该索引节点搜索仅返回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✽
,或者为什么它会尝试。幸运的是,ls
并stat 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
当出现在屏幕上时。
两种可能的解决方案:
使用具有制表符补全功能的 shell(zsh 或 bash)。根据提示执行:
rm -rf akorg<tab>
。 Zsh 至少会完成文件名,并根据需要转义 shell 特殊字符。单行,有点冒险:
rm -rf akorg?
你可以手动执行#2,例如:ls -1 > filenames
。在名为“filenames”的文件上使用某些文本编辑器删除除有问题的目录之外的所有行。rm -rf
向该行添加前缀。退出编辑器。作为 shell 脚本执行:sh filenames