我有一个这样的目录结构:
./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
作为一种替代方法,您不需要诸如rename
、basename
等外部程序 - 所有程序都可以在参数扩展中处理bash
:-
find SourceDir ... | while read -r f; do mv "$f" "TargetDir/${f//\//_}"; done
扩展有点难以理解,因此发生的情况如下:-
- 使用 找到要移动的文件
find
。 - 每个文件名依次读入
$f
。 - 参数
read -r
和扩展名周围的双引号处理奇怪的名称,包括文件名中的空格。 - 该
mv
命令将名称移动a/b/c
为TargetDir/a_b_c
。 - 目标扩展用 替换每个
/
,_
但它看起来令人生畏,因为/
它是替换语法的一部分。 - 一般形式为,它用替换展开式中
${param/old/new}
的第一个实例。old
new
- 这里需要的形式是
${param//old/new}
,它取代每一个扩展中的old
by实例。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 还支持复制、链接或附加文件。