ben*_*sky 9 command-line files mv
我从一个目录中移动了所有文件mv
,但不小心在目标位置路径中打错了字。
系统返回一条消息,该目录不存在,但我的源目录中的文件已被删除。
这是一个错误吗?将文件移动到不存在的位置是否应该删除正在移动的文件?(这是在 Ubuntu 18.04.2 LTS 上。)
具体是:
test.txt
文件。/ben
用sudo
。/ben
不存在。命令和输出是:
ben.b@c-w46:~/Desktop/test-folder$ sudo mv test.txt /ben
ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory
Run Code Online (Sandbox Code Playgroud)
Eli*_*gan 14
在你实际运行的命令中,你没有丢失任何东西!它成功地重命名test.txt
为/ben
. 假设test.txt
是一个常规文件,那么新文件也是如此/ben
(毕竟它们是同一个文件)。
你看到的原因bash: cd: /ben: Not a directory
是它在罐头上写的:/ben
不是目录。您仍然可以访问该文件。
如果您想避免这种错误并mv
在目标不是目录时强制失败,请/
在其上写一个结尾或使用-t dir
. 例如,其中任何一个都可以防止您遇到的(非常小的!)问题(sudo
必要时):
mv test.txt /ben/ # no action, unless `/ben` is an existing directory
Run Code Online (Sandbox Code Playgroud)
mv -t /ben test.txt # same deal, -t doesn't accept regular-file operands
Run Code Online (Sandbox Code Playgroud)
mv -t /ben/ test.txt # you can even do both if you want
Run Code Online (Sandbox Code Playgroud)
关于您的问题中描述的一般情况的信息——关于通过尝试移动文件而丢失文件——以及可能出错和不可能出错的信息。
正如Rinzwind 所说,当您尝试使用单个mv
命令将文件移动到不存在的目标目录时,不应导致数据丢失。但是,如果您运行mv
多次(例如在 shell 循环中),则可能会发生这种情况。
例如,假设我有:
ek@Apok:~/tmp$ ls -F
dest/ file02.txt file04.txt file06.txt file08.txt file10.txt
file01.txt file03.txt file05.txt file07.txt file09.txt
Run Code Online (Sandbox Code Playgroud)
所有这些文件移动到dest
,我应该通过所有他们的名字mv
,像一个命令mv file*.txt dest/
或mv file*.txt dest
。在任何一种情况下——也就是说,无论我是否用斜杠写目标目录名称——这都是正确的。在任何一种情况下,如果我拼错了目标目录名称(例如,通过写入dst
),我会收到错误mv: target 'dst' is not a directory
并且不会丢失任何数据。
但是,假设我拼错了dst
,省略了尾随/
,并运行了多个mv
命令。那会很糟糕,因为当目标mv
是一个普通文件时,mv
替换它!
ek@Apok:~/tmp$ mv file01.txt dst # bad if dst exists but isn't a directory
ek@Apok:~/tmp$ mv file02.txt dst # bad, I just lost the old file01.txt!
Run Code Online (Sandbox Code Playgroud)
这就是为什么很多人总是喜欢与尾部写入目标目录/
中mv
:
ek@Apok:~/tmp$ mv file03.txt dst/
mv: failed to access 'dst/': Not a directory
Run Code Online (Sandbox Code Playgroud)
您可以使用mv -i
在覆盖之前询问您,或者mv -n
静默不覆盖。否则,mv
仅在覆盖之前询问您目标是否为只读文件。考虑这一点的一个原因是它涵盖了其他情况,例如mv file01.txt dest/
您没有意识到dest/file01.txt
存在并且不想覆盖它的情况。
你也可以在命令的末尾使用-t dest
而不是写dest
,例如,mv -t dest file*.txt
。如果dest
是常规文件,这将拒绝操作,无论您是否编写了尾随/
.
使用自动化机制来运行多个此类命令可能会严重加剧问题。例如,正如所写的命令for f in file*.txt; do mv "$f" dest/; done
是不必要的复杂但安全,因为如果我不小心指定了文件dst
而不是目录dest
(但保留了斜杠!),它会给我mv: failed to access 'dst/': Not a directory
每个文件一个错误。但是,如果我省略了结尾的/
,那么它会将每个文件重命名为dst
,替换之前的dst
,并且只会保留最后一个文件。
使用 可以实现类似的不良结果find
,包括在可能合理使用的情况下find
(但不同,但仍需格外小心)。例如,假设我想将file*.txt
整个目录树(除了dest
它本身)中与 glob 匹配的所有文件移动到目录dest
. 我可能首先想到使用这个:
find . -path ./dest -prune -o -name 'file*.txt' -exec mv {} dest/ \; # bad, don't use
Run Code Online (Sandbox Code Playgroud)
因为我包含了一个尾随/
, 写作dest/
而不是dest
,dst
即使我写dst
而不是dest
. 但是它有一个相关的问题,它会覆盖它已经复制的文件,如果目录树不同部分的文件具有相同的名称。例如,如果有一个a/file01.txt
和一个b/file01.txt
,一个会覆盖另一个。为了避免这种情况,最好使用这样的东西:
find -path ./dest -prune -o -name 'file*.txt' -exec mv -it dest/ {} \; # okay
Run Code Online (Sandbox Code Playgroud)
另一个好处-t dir
是,因为它允许您在移动项目之前指定目标目录,所以它与 的+
形式兼容-exec
,其中将多个项目传递给一个命令,从而运行更少的命令(通常只有一个):
find -path ./dest -prune -o -name 'file*.txt' -exec mv -it dest/ {} + # good
Run Code Online (Sandbox Code Playgroud)
在这两种情况下(除了\;
vs.之外,它们是相同的+
)我还传递了-i
在每个会覆盖文件的操作之前进行提示的选项。如果你只想默默地跳过那些,写n
而不是i
. 如果您想先测试您的find
命令,您可以在命令的其余部分echo
之后-exec
但之前编写以打印将运行的内容。例如:
ek@Apok:~/tmp$ find -path ./dest -prune -o -name 'file*.txt' -exec echo mv -it dest/ {} +
mv -it dest/ ./file02.txt ./file06.txt ./file10.txt ./file09.txt ./file01.txt ./file04.txt ./file05.txt ./file07.txt ./file03.txt ./file08.txt
Run Code Online (Sandbox Code Playgroud)
(当然,那是在我展示的原始目录中,所有要移动的文件都在同一位置,因此哪里find
是矫枉过正,最复杂的合理使用命令是mv -it dest/ file*.txt
。)
不,你的建议应该(!)不可能。您可能需要更好地查看目的地。使用history
可获取前发出的命令的列表。
几件事:
如果有动作完成...
请参阅info coreutils 'mv invocation'
(在线版本https://www.gnu.org/software/coreutils/manual/html_node/mv-invocation.html#mv-invocation)了解 mv 的工作原理以及更具体的这一部分:
它首先使用一些与 'cp -a' 使用的代码相同的代码来复制请求的目录和文件,然后(假设复制成功)删除原始文件。如果复制失败,则删除复制到目标分区的部分。如果您要将三个目录从一个分区复制到另一个分区,并且第一个目录的复制成功,但第二个没有成功,则第一个将保留在目标分区上,第二个和第三个将保留在原始分区上。
所以一个动作由两部分组成:
cp -a
mv
移动的移除部分在确认复制已正确完成后完成。
如果您的 mv 包含多个文件,则复制和移动在两者之间完成。所以一个
mv a b c d e f /dir/
Run Code Online (Sandbox Code Playgroud)
会做一个
cp a /dir/
rm a
...
cp f /dir/
rm f
Run Code Online (Sandbox Code Playgroud)
因此,当 a 和 f 之间出现问题时,它将完成 a 的移动,直到出现问题的位置。这也适用于使用通配符。
关于编辑
sudo mv test.txt /ben
Run Code Online (Sandbox Code Playgroud)
这会将 test.txt 移动到 / 并将其重命名为 ben。和
ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory
Run Code Online (Sandbox Code Playgroud)
正确错误。做一个
ls -l /ben
Run Code Online (Sandbox Code Playgroud)
它会显示文件。
如果要将文件移动到目录,则始终应该做的是附加 /。
sudo mv test.txt /ben/
Run Code Online (Sandbox Code Playgroud)
会出错,因为 /ben/ 不存在。
归档时间: |
|
查看次数: |
5526 次 |
最近记录: |