我想将大约 1000 个 mp3 文件从包含复杂嵌套目录结构的名为“music”的目录移动到名为“mp3s”的单个目录,以便我可以在车中收听它们。
我使用的命令是:
find music -name '*mp3' -exec mv -v -t mp3s {} +
然而,当我执行命令时发生了一些奇怪的事情。命令完成后,我注意到省略了四个文件。这些文件是:
"music/Michael Hedges/Michael Hedges - Taproot/06 - Chava's Song.mp3"
'music/Michael Hedges/Michael Hedges - Aerial Boundaries/04 - Ragamuffin.mp3'
'music/Jonas Hellborg/1988 - Bass/07. Blues For LW.flac.mp3'
'music/Jonas Hellborg/1988 - Axis/03. Roman.flac.mp3'
我再次执行了完全相同的命令,这一次先前省略的四个文件已按预期移动。
我无法想象为什么find
会做出这样出乎意料的事情。为什么会发生这种情况?
在 Ubuntu 上的 bash shell 中执行。
答案1
假设:名称冲突
想象一下在某个时候命令是这样的:
mv -v -t mp3s … …/some_dir/foo.mp3 … …/another_dir/foo.mp3 …
foo.mp3
fromsome_dir
被移至mp3s
,但foo.mp3
fromanother_dir
被触发:
mv: will not overwrite just created 'mp3s/foo.mp3' with '…/another_dir/foo.mp3'
显然,该消息在由 引起的消息群中没有被注意到-v
。
后来第二个find
尝试再次移动…/another_dir/foo.mp3
,但是这次没有…/some_dir/foo.mp3
,所以mp3s/foo.mp3
不被认为是“刚刚创建”,它被覆盖了。
注意-exec mv … {} +
可能会运行多个mv
。如果…/some_dir/foo.mp3
和…/another_dir/foo.mp3
被分配给 的不同调用mv
,则后者mv
不会被视为mp3s/foo.mp3
“刚刚创建”。这意味着在您的情况下可能存在更多名称冲突,并且某些文件被悄悄覆盖。只有具有相同基名的文件被分配给相同的名称冲突mv
才会导致某些文件无法移动。
概念证明
$ mv --version
mv (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Parker, David MacKenzie, and Jim Meyering.
$
$ mkdir -p music/a music/b music/c mp3s
$ touch music/a/A music/b/B music/c/A
$ tree --noreport
.
|-- mp3s
`-- music
|-- a
| `-- A
|-- b
| `-- B
`-- c
`-- A
$ find music -type f -exec mv -v -t mp3s {} +
renamed 'music/a/A' -> 'mp3s/A'
renamed 'music/b/B' -> 'mp3s/B'
mv: will not overwrite just-created 'mp3s/A' with 'music/c/A'
$ tree --noreport
.
|-- mp3s
| |-- A
| `-- B
`-- music
|-- a
|-- b
`-- c
`-- A
$ find music -type f -exec mv -v -t mp3s {} +
renamed 'music/c/A' -> 'mp3s/A'
$ tree --noreport
.
|-- mp3s
| |-- A
| `-- B
`-- music
|-- a
|-- b
`-- c
$