我有一个这样的目录结构:
Project/
|
+--Part1/
| |
| +--audio.mp3
|
+--Part2/
| |
| +--audio.mp3
|
+--Part3/
| |
| +--audio.mp3
...
我想要最终得到名为 Part1.mp3、Part2.mp3 等的文件。
每个文件夹仅包含一个文件,因此不存在破坏文件或处理多个同名文件的风险。
我觉得我可以用某种find
/xargs
命令加上cut
and来做到这一点mv
,但我不知道如何实际形成命令。
答案1
这些示例可以在任何 POSIX shell 中运行,不需要外部程序。
这会将 Part*.mp3 文件存储在与项目目录相同的级别:
(cd Project && for i in Part*/audio.mp3; do echo mv "$i" ../"${i%/*}".mp3; done)
这会将 Part*.mp3 文件保留在项目目录中:
for i in Project/Part*/audio.mp3; do echo mv "$i" ./"${i%/*}".mp3; done
这些解决方案使用 shellpattern matching
parameter expansion
来生成新文件名。
${parameter%word} Remove Smallest Suffix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the smallest portion of the suffix matched by the pattern deleted.
答案2
如果你有 perl rename
(有时称为prename
),你可以这样做:
( cd Project && rename 's!(.+)/(.+)(\.mp3)!$1.$3!' */audio.mp3 )
这将获取与 shell glob 匹配的每个文件名*/audio.mp3
,并将其拆分为目录、文件名和扩展组件。然后它会丢弃文件名部分并重命名该文件。
使用rename -n ...
来查看会发生什么,或者使用-v
而不是-n
观察它运行时发生的情况。
答案3
pax -rwls'|.*/\(.*\)/audio\(\.mp3\)$|\1\2|p' \
-s'|.*||' /path/to/Project .
这将使用 POSIXpax
命令行归档实用程序在当前目录中创建硬链接,命名为树中parent_dirs_base.mp3
每个找到的根目录audio.mp3
/path/to/Project
。执行此操作时,它将打印对 stderr 所做的任何文件名修改。
用于-k
防止它可能覆盖与其链接目标具有相同名称的现有文件,或者更好的是,在运行之前首先更改为空目录。
在我看来,首先进行硬链接而不是直接mv
链接您想要使用的文件有一个显着的优势:那就是您有机会验证您期望的结果与您得到的结果是否相同前删除原件。检查后您可以:
find /path/to/Project -name audio.mp3 -exec rm {} +
...清理文件链接并将其减少一个。
答案4
具有 Perl 风格的 Bash
for file in `find . -type f -name "*.mp3"`;
do
dir=$(dirname $file);
bdir=$(basename $dir);
bname=$(basename $file);
new=$bdir.$bname;
newname=${new//\.\./};
newname_with_path=$dir/$newname
if [ "$file" != "$newname_with_path" ]
then
echo mv -u $file $newname_with_path ;
fi
done
# replace 2 dots with nothing
# bash 4.1.2 centos 6.4 no problem with or without bashslash
newname=${new//../};