将文件从子目录移动到单个目录并在原始目录名称前加上前缀

将文件从子目录移动到单个目录并在原始目录名称前加上前缀

我有一个这样的目录结构:

./a/1.png
./a/2.png
./a/3.png
./b/1.png
./b/2.png
./b/3.png
./c/1.png
...

我想将子目录中的所有文件移动到新目录中,因此它们的名称类似于

../dest/a_1.png
../dest/a_2.png
../dest/a_3.png
../dest/b_1.png
../dest/b_2.png
../dest/b_3.png
../dest/c_1.png
...

如果不编写脚本逐个文件执行此操作,我能找到的最接近的方法是使用find--backup=numbered选项将我的文件压缩到单个目录但最终会丢失文件名中的目录上下文。

有没有简洁的方法来实现这一点?

答案1

使用 Perl 的独立rename命令:

rename -n 's|/|_|; s|^|dest/|' */*.png

输出:

a/1.png 重命名为 dest/a_1.png
a/2.png 重命名为 dest/a_2.png
a/3.png 重命名为 dest/a_3.png
b/1.png 重命名为 dest/b_1.png
b/2.png 重命名为 dest/b_2.png
b/3.png 重命名为 dest/b_3.png
c/1.png 重命名为 dest/c_1.png

如果一切正常,请删除选项-n

答案2

使用 Bash 4 和递归通配符 ( shopt -s globstar):

for f in **/*.png; do
  dn=$(basename "$(dirname "$f")")
  bn=$(basename "$f")
  mv -- "$f" "../dest/${dn}_${bn}"
done

请注意,dirname /foo/bar/baz返回的/foo/bar不仅仅是bar,这就是为什么您必须调用basename结果来获取,以防bar您正在从另一个父文件夹工作。

答案3

作为一种替代方法,您不需要诸如renamebasename等外部程序 - 所有程序都可以在参数扩展中处理bash:-

find SourceDir ... | while read -r f; do mv "$f" "TargetDir/${f//\//_}"; done

扩展有点难以理解,因此发生的情况如下:-

  • 使用 找到要移动的文件find
  • 每个文件名依次读入$f
  • 参数read -r和扩展名周围的双引号处理奇怪的名称,包括文件名中的空格。
  • mv命令将名称移动a/b/cTargetDir/a_b_c
  • 目标扩展用 替换每个/_但它看起来令人生畏,因为/它是替换语法的一部分。
  • 一般形式为,它用替换展开式中${param/old/new}的第一个实例。oldnew
  • 这里需要的形式是${param//old/new},它取代每一个扩展中的oldby实例。new
  • 为了使/成为旧字符串的一部分,它必须被转义为\/,因此相当晦涩${f//\//_}:第一个/引入了替换语法,第二个/指定了替换每一个,第三个(转义)/是旧字符串,最后一个/引入新字符串(_)。

我并不经常在脚本中看到这种形式的扩展,但它值得了解,因为它有时非常有用。

有些文件名会破坏这一点(嵌入的换行符,以及前导或尾随空格,尽管后者有两种方法:-

  • 使用read -r而不是read -r f并使用REPLY而不是f
  • 使用while f="$(line)"而不是read -r f

后者更简洁,但使用外部程序line,该程序可能并非在所有系统上都可用,尽管它可以编码为一个函数:

line() { read -r; r=$?; echo "$REPLY"; return $r; }

答案4

作为替代方案改名, 有韓國,它使用标准外壳图案。

从手册页中:

韓國 移动(或复制、追加或链接,按指定)与模式到指定的目标名称模式。此多重操作是安全执行的,即不会因目标名称与现有文件名或其他目标名称冲突而导致意外删除文件。此外,在执行任何操作之前,韓國尝试检测由指定的整个操作集所导致的任何错误,并让用户选择是避开有问题的部分继续操作还是中止。

对于您的用例:

mmv -n '*/*' 'dest/#1_#2'
a/1.jpg -> dest/a_1.jpg
a/2.jpg -> dest/a_2.jpg
a/3.jpg -> dest/a_3.jpg
b/1.jpg -> dest/b_1.jpg
b/2.jpg -> dest/b_2.jpg
b/3.jpg -> dest/b_3.jpg
c/1.jpg -> dest/c_1.jpg
c/2.jpg -> dest/c_2.jpg
c/3.jpg -> dest/c_3.jpg

喜欢改名,‘-n’ 表示不执行。删除它以进行实际重命名。

除了重命名,mmv 还支持复制、链接或附加文件。

相关内容