错误:linux“查找”首次运行时未查找/重命名包含字符串的所有目录

错误:linux“查找”首次运行时未查找/重命名包含字符串的所有目录

find使用以下命令在文件结构(数百个文件夹,大约 4 层深)上运行find "/media/$disk/_all" -depth -type d -exec/execdir rename -d 's/ 1000k/ [1000k]/' "{}" \;:我反复指出,某些包含 1000k 的文件夹仍未重命名,我注意到其中一些在第二次运行该命令时被重命名。为什么不全部都在第一次运行呢?

另外,我注意到输出经常有“无法重命名/media/some_original /media/some_renamed:没​​有这样的文件或目录”,之后我检查,some_original 成功重命名为 some_renamed。

我猜测的第一个错误是由于 find 没有遍历所有树而发生的,第二个错误是由于 find 对某些/全部树进行并调用 exec 两次?条目。我后来添加了 -depth 选项,以确保“子”文件夹在“父”文件夹之前被重命名,但它没有帮助(在我的情况下,当我注意到错误时,我没有注意到由于被重命名而导致的几个级别)。

我无法通过网络搜索找到答案。这里可能有什么问题?

系统是Linux Mint 20.1。

添加:我已经检查过,使用 ls -lR /path/to/folder | 在结构中没有找到任何链接grep ^l 来自https://stackoverflow.com/questions/8513133/how-do-i-find-all-of-the-symlinks-in-a-directory-tree

磁盘安装方式如下:输入 ext4 (rw,nosuid,nodev,relatime,stripe=8191,uhelper=udisks2)

答案1

初步说明

  • 这个答案是试图解释可能发生的事情,而不是对确实发生的事情做出明确的解释。这是因为:

    • OP 尝试了该命令的不同变体(带或不带-depth、带-exec-execdir),问题正文中发布的确切命令应持保留态度;
    • 每次尝试都可能修改目录树,但没有日志说明由于确切的命令而发生的重命名;
    • 同样,没有错误日志;
    • 在分析问题(在评论和聊天中)后,我们注意到很少有不同的问题会生成类似的错误消息(因此很容易假设只有一个问题)。

    由于这些原因,尝试创建一个单一的MCVE(以一个精确的目录树和一个精确的命令的形式find)失败。我们一致认为,最好是创建一个涵盖可能问题的答案,并考虑到未来的读者。这个答案就是这样的答案。

  • 超过一个rename。所讨论的语法适用于rename与 Larry Wall 和 Robin Barker 相关的 Perl 脚本。我认为这是rename使用过的。不过,本答案中涵盖的问题并不特定于此rename


可能发生了什么

No such file or directory当您使用 时,find可能会产生一些不同的问题rename

首先,我们来简化一下这个例子。设目录结构为:

/a/b/c.1/c.2/d

命令是:

find /a/b -exec rename s/c/X/ {} \;

该命令将产生:

find: '/a/b/c.1': No such file or directory

这是因为在尝试下降到 之前没有-depth find进程。处理时,将其重命名为,但不知道名称更改。它尝试处理更深层次的文件,但已不存在。这非常类似于c.1c.2c.1renameX.1findc.1c.1find与使用rm -r

该命令的第二次迭代将看到/a/b/X.1/c.2/d并成功重命名c.2X.2.尽管如此,它还是会抱怨c.2不在那里。第三次迭代将不执行任何操作,也不抱怨任何内容。

在对目录本身执行任何操作之前,您需要告诉find处理目录中的文件。这就是-depth目的。


即使-depth有了也可能仍然存在问题。再次,具有以下结构:

/a/b/c.1/c.2/d

并运行“固定”命令:

find /a/b -depth -exec rename s/c/X/ {} \;

我们将得到:

Can't rename /a/b/c.1/c.2/d /a/b/X.1/c.2/d: No such file or directory
Can't rename /a/b/c.1/c.2 /a/b/X.1/c.2: No such file or directory

这些消息的来源并不明显,rename但确实如此。问题d先处理一下,rename/a/b/c.1/c.2/d改成/a/b/X.1/c.2/d。就像,如果不存在,mv /a/b/c.1/c.2/d /a/b/X.1/c.2/d你就不能这样做。/a/b/X.1/c.2/稍后(在处理时c.2)你不能,mv /a/b/c.1/c.2 /a/b/X.1/c.2因为X.1它还不存在。

(默认情况下,您可能会惊讶rename地尝试某些无法成功的操作。注意,当不存在时,该命令mv /a/b/c.1/c.2/d /a/b/X.1/c.2/d不会成功。当已经存在时,此命令仍然是正常的。在这种情况下, 的默认行为同样正常。)X.1X.1/c.2/c.1/c.2/rename

在我们的例子中,X.1出现了whenc.2被默默地重命名为,X.1但这发生在稍后。该命令的第二次迭代将在处理时抱怨d,它将设法重命名c.2。第三次迭代将不执行任何操作,也不抱怨任何内容。

请注意,如果您使用了/c.0not/a且命令为no find /c.0/b …,则 norename将会成功,并且任何次数的迭代都将是徒劳的。

问题是rename s/c/X/尝试更改c路径中的第一个,即使这c是在目录组件中,而不是在文件名中。至少有两种方法可以解决这个问题。


您可以使用rename -d。此选项rename仅对文件名起作用。以下命令:

find /c.0/b -depth -exec rename -d s/c/X/ {} \;

将成功更改/c.0/b/c.1/c.2/d/c.0/b/X.1/X.2/d(因此即使c.0不是问题)。

-d是一个相对较新的选择。一般来说,您rename可能不支持它。在这种情况下,使用-execdir而不是-exec

find /c.0/b -depth -execdir rename s/c/X/ {} \;

(一般来说,您find可能支持也可能不支持-execdir。)

它之所以有效,是因为在处理时d,字符串rename处理的是 now ./d,而不是/c.0/b/c.1/c.2/d;同样,处理时c.2,是./c.2,不是/c.0/b/c.1/c.2。该工具每次都在各自的父目录中工作,因此相对路径有效。通过不在字符串中包含完整路径,我们得到rename -dwithout的行为-d

嗯,差不多了。如果您想rename用点做某事(例如更改c.2为等),那么或c-2中的前导点就是您需要处理的内容。 with就不存在这样的问题,无论你使用或;所以如果可以的话就使用。./d./c.2-d-exec-execdirrename -d


最后说明

有问题的命令包括-depthrename -d。 OP 明确指出:

-depth后来添加了选项[...]

所以可能缺乏-depth是最初的问题。但是之后:

[添加-detph]没有帮助

考虑到这一点并注意到错误 ( Can't rename …) 来自rename,我得出的结论-d是并不总是存在或者我遗漏了一些东西。现在我认为find -depthwithrename -d应该是稳健的。假设OP真的失败了,我还无法解释这一点。

相关内容