使用find和xargs移动文件时出现“mv:无法查找”错误。

12 浏览
0 Comments

使用find和xargs移动文件时出现“mv:无法查找”错误。

我正在编写一个bash脚本,需要将源文件夹中的所有文件和文件夹(递归地)移动到目标文件夹中。

为了尽可能地使其健壮,并解决可能的“参数列表过长”错误,我选择使用“find”命令(安全地确定要移动的文件)管道到“xargs”(高效地将移动操作组合在一起)。我还使用“-print0”和“-0”来解决可能出现的空格问题。

我编写了以下测试脚本:

#!/bin/bash

# 创建测试源文件结构和目标文件夹

mkdir -p sourceDir/{subdir1,subdir\ with\ space\ 2}

mkdir -p destDir

touch sourceDir/subdir1/{a1.txt,noExtension1,file1\ with\ space.txt}

touch sourceDir/subdir\ with\ space\ 2/{a2.txt,noExtension2,file2\ with\ space.txt}

# 从源文件夹移动文件/文件夹到目标文件夹

find sourceDir -mindepth 1 -print0 | xargs -0 mv --target-directory=destDir

看起来似乎工作正常(即文件被移动),但是出现了很多错误,如下所示:

mv: 无法统计“sourceDir/subdir with space 2/file2 with space.txt”:没有那个文件或目录

mv: 无法统计“sourceDir/subdir with space 2/noExtension2”:没有那个文件或目录

mv: 无法统计“sourceDir/subdir with space 2/a2.txt”:没有那个文件或目录

mv: 无法统计“sourceDir/subdir1/file1 with space.txt”:没有那个文件或目录

mv: 无法统计“sourceDir/subdir1/noExtension1”:没有那个文件或目录

mv: 无法统计“sourceDir/subdir1/a1.txt”:没有那个文件或目录

对于我脚本中指定的源文件来说,难道不应该有一种方法可以在不生成错误的情况下执行此操作吗?

为什么会生成这些错误(因为实际上文件和文件夹确实被移动了)?

0
0 Comments

在使用find命令通过xargs移动文件时出现"mv: cannot stat"错误的原因是,当使用find命令直接移动文件时,它会为每个单独的文件执行mv命令。而如果需要移动的文件数量很多,比如成千上万个文件,这样的操作会变得非常慢和低效。通过使用xargs(或者在-exec中使用+),可以提高效率。

解决这个问题的方法是,使用xargs命令来批量处理文件移动操作。通过将find命令的输出作为xargs的输入,并将mv命令作为参数传递给xargs,可以一次性移动多个文件,而不是为每个文件执行一次mv命令。

下面是一个示例命令,演示如何使用find和xargs来移动文件:

$ find [...] -print0 | xargs -0 mv -t [...]

在这个命令中,-print0选项告诉find命令以空字符作为分隔符输出文件列表,-0选项告诉xargs命令以空字符作为分隔符读取输入。-t选项告诉mv命令将文件移动到指定的目标目录。

通过使用xargs来批量处理文件移动操作,可以大大提高效率,特别是当需要移动大量文件时。这种方法避免了为每个文件执行mv命令的开销,使移动操作更加高效。

希望这篇文章能够帮助你理解在使用find命令通过xargs移动文件时出现"mv: cannot stat"错误的原因,并提供了解决这个问题的方法。通过使用xargs来批量处理文件移动操作,可以提高效率并避免低效的单个文件移动操作。

0
0 Comments

问题出现的原因是原始的find命令列出了每个文件的路径,然后尝试移动每一个文件。一旦顶级文件夹被移动,就没有必要移动任何子文件夹或文件了,但脚本仍然在尝试移动它们。解决方法是添加-maxdepth 1选项,只移动顶级文件和文件夹。

下面是一个演示此问题的脚本(不执行实际的移动操作):

#!/bin/bash
mkdir -p sourceDir/{subdir1/subsubdir1,subdir\ with\ space\ 2}
touch sourceDir/subdir1/{subsubdir1/deeperFile.log,a1.txt,noExtension1,file1\ with\ space.txt}
touch sourceDir/subdir\ with\ space\ 2/{a2.txt,noExtension2,file2\ with\ space.txt}
touch sourceDir/rootFile.txt
echo -e "\n--- Output of 'ls -1: sourceDir':"
echo "$(ls -1 sourceDir)"
echo -e "\n--- original incorrect attempt was trying to move each of the following:"
find sourceDir -mindepth 1
echo -e "\n--- working attempt only needs to move each of the top level files/folders, everything underneath any folders will get moved automatically"
find sourceDir -mindepth 1 -maxdepth 1

脚本输出如下:

--- Output of 'ls -1: sourceDir':
rootFile.txt
subdir1
subdir with space 2
--- original incorrect attempt was trying to move each of the following:
sourceDir/rootFile.txt
sourceDir/subdir with space 2
sourceDir/subdir with space 2/file2 with space.txt
sourceDir/subdir with space 2/noExtension2
sourceDir/subdir with space 2/a2.txt
sourceDir/subdir1
sourceDir/subdir1/file1 with space.txt
sourceDir/subdir1/noExtension1
sourceDir/subdir1/a1.txt
sourceDir/subdir1/subsubdir1
sourceDir/subdir1/subsubdir1/deeperFile.log
--- working attempt only needs to move each of the top level files/folders, everything     underneath any folders will get moved automatically
sourceDir/rootFile.txt
sourceDir/subdir with space 2
sourceDir/subdir1

如果只使用`-type d`选项,则会忽略任何顶级文件。没有指定`-maxdepth 1`会列出任何子子文件夹,并且移动它们会失败。可以查看下面的更新回答以获取完整详细信息。

在你的问题中,你只提到了目录。所以我添加了`-type d`选项。第一行说:“(递归地)移动所有文件和文件夹”,虽然在示例脚本中可能没有明确说明。

0
0 Comments

"mv: cannot stat"错误是在使用find命令通过xargs移动文件时出现的。出现这个问题的原因是,默认情况下find命令的输出是从父目录开始的,然后是包含的目录。在你的目录结构上运行简单的find命令会得到以下输出:

sourceDir/subdir1
sourceDir/subdir1/a1.txt
sourceDir/subdir1/noExtension1
sourceDir/subdir1/file1 with space.txt
sourceDir/subdir with space 2
sourceDir/subdir with space 2/noExtension2
sourceDir/subdir with space 2/file2 with space.txt

如果你将这个输出用于xargs或-exec,它会先处理父目录,然后处理其内容。在这种情况下,你的命令会正常执行,并将整个sourceDir/subdir1目录移动到destDir/subdir1。之后,在sourceDir中就没有像sourceDir/subdir1/a1.txt或sourceDir/subdir1/noExtension1这样的文件/目录了,因为它们已经被移动到destDir。

为了避免这种情况,可以使用-depth选项。

-depth  优先处理每个目录的内容,然后再处理目录本身。

在你的情况下,你可以添加-type d选项将顶层源目录移动到destDir。

find sourceDir -mindepth 1 -type d -print0 | xargs -0 mv --target-directory=destDir

或者

find sourceDir -mindepth 1 -type d -exec mv -t destDir "{}" \+

这样可以解决你的问题。

感谢你的反馈,但是这仍然不起作用。如果没有我自己回答中提到的-maxdepth 1,你的解决方案会列出任何子子文件夹,并且再次无法移动它们。请参考我的更新答案获取详细信息。

同意,-maxdepth 1会使它更通用。

0