我正在尝试将一堆名为folder.jpg 的文件复制到一个文件夹中。问题是因为所有文件都被命名为相同的东西,我需要在此过程中重命名它们。我知道我可以使用 sed 来完成此操作,但我想将它们重命名为父文件夹的一部分的名称。这是我找到并复制文件所得到的
cp $(find . -iname "folder.jpg") .albumart/
文件夹结构是 ./artist/artist.year.album/folder.jpg ,我想使用父文件夹(或只是其中的一部分)来命名文件。有人可以帮我用一个衬垫来完成任务吗?为了让事情变得更棘手,一些文件夹还有一层 CD1 和 CD2,如果它们存在,我想忽略它们(例如 ./artist/artist.year.album/CD1/folder.jpg)
答案1
假设您有bash
,此版本仅采用您的文件夹结构(例如./foo/bar/baz/folder.jpg
)并用下划线替换所有斜杠(例如,这样您就得到了foo_bar_baz_folder.jpg
):
find . -iname folder.jpg -exec bash -c 'for x; do x=${x#./}; cp -i "$x" ".albumart/${x//\//_}"; done' _ {} +
请注意,无论您做什么,只要将文件从多个位置移动到同一目标,总是有可能发生名称冲突。
答案2
使用 zsh:
autoload zmv
zmv -n -C '(**/)folder.jpg' '.albumart/${1:t}.jpg'
高兴的时候就删掉-n
。
这将避免名称冲突(如果两个替换解析为相同的名称,则会失败并出现错误),例如:
$ zmv -n -C '(**/)folder.jpg' '.albumart/${1:t}.jpg'
zmv: error(s) in substitution:
b/c/folder.jpg and a/b/c/folder.jpg both map to .albumart/c.jpg
答案3
不要解析 的输出find
。如果?*\[
文件名中存在空格或全局字符,则会中断。如果您使用find
,请使其通过操作调用命令-exec
。在操作中调用 shell-exec
来执行必要的字符串转换。
find -name folder.jpg -exec sh -c '
dir=${0%/*} # stip off the file name
case $dir in */CD[0-9]) dir=${dir%/*};; esac
cp -ip "$0" ".albumart/${dir##*/}.jpg"
' {} \;
兹什的兹马夫通常是进行此类复制的最简单方法。
zmv -C -o-p -w '**/*.jpg' '.albumart/${${${1%/}/CD<->}##*/}.jpg'
一些解释:
- 一般语法是
zmv OPTIONS… SOURCE_PATTERN REPLACEMENT
. -w
打开通配符组匹配。在替换文本中,$1
指的是 匹配的部分**/
(/
除非匹配的文本为空,即文件位于顶级目录),并且指$2
的是 匹配的部分。*
*.jpg
- 模式和替换文本都必须受到保护以防止扩展:它们需要按字面传递给
zmv
. - 要理解
${${${1%/}/CD<->}##*/}
,就要从内到外。首先采取$1
.去掉最后一个/
(如果有的话)。去掉最终的模式匹配/CD<->
(如果有的话)<->
匹配一位或多位数字)。最后关闭除最后一个目录组件之外的所有内容。 - 如果想用下划线替换空格,再添加一层参数扩展:
${${${${1%/}/CD<->}##*/}// /_}
。
答案4
显然这个答案迟到了,但希望其他人可能会发现它有用。
for i in $(find . -type f -iname "folder.jpg" -printf "%P\n") ; do t=$(echo $i | sed 's|/|\.|g'); cp $i TARGETDIR/$t ; done
的作用是从的输出中-printf "%P\n"
去除前导。./
find
将find
结果 ( $i
)回显sed
并进行更改,在本例中 sed 替换/
为.
,并将整个结果的值分配给t
然后只需将 找到的文件(find
在$i
本例中)复制到具有新名称的 TARGETDIR 中$t
。
发现:./artist/artist.year.album/folder.jpg
产量: TARGETDIR/artist.artist.year.album.folder.jpg