zsh:如果子文件夹中的文件具有相同的名称,则重命名文件

zsh:如果子文件夹中的文件具有相同的名称,则重命名文件

有以下文件结构:

charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
this-file.waldo
another-file.waldo

我想重命名根文件夹中的所有文件,在本例中this-file.waldoanother-file.waldo.如果在任何子文件夹中存在与 .waldo 文件具有相同基本名称的文件,那么我想使用包含同名文件的子文件夹的名称重命名 .waldo 文件,如下所示:

charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
charlie.waldo
foxtrot.waldo

当且仅当子文件夹具有共享相同基本名称的文件时,才必须重命名该文件,并且必须使用与子文件夹相同的名称来重命名该文件。

实现这一目标最有效的方法是什么?

  • 始终存在 .waldo 文件。
  • 如果没有共享基本名称的文件,它应该忽略并继续下一个文件,直到找到匹配项。
  • 文件名是正常的操作系统文件名,所以是的,可能存在 &()[]# 等。

答案1

这可能是这样的:

for f (*.waldo(N)) (){ (($#)) && echo mv -- $f $1:h.waldo; } */$f:r.*(NY1)

echo如果满意,请删除(空运行))。

那里发现了一些不太常见的 zsh 功能:

  • for f (values) action: for 循环的简写形式(类似于 perl 语法)
  • () { body; } args: 匿名函数
  • $var:r: root 名称(没有扩展名的部分,如 csh/vim 中...)
  • $var:h: head (目录名,如 csh/vim 中)
  • (N): Nullglob glob 限定符:所以如果没有匹配,它不会报告错误:
  • (Y1):在第一个匹配 glob 限定符后停止。

答案2

首先,您获取当前目录中所有文件的列表

files=(*(.DoN))

然后,你对他们每个人做一些事情:

for file in $files; do
  # get the basename
  bname="${file%%.*}"
  # look for matches in subfolders
  typeset -a matches_in_subfolders
  matches_in_subfolders=*/${bname}*
  # Check whether list of matches is longer than 0
  if [ ${#matches_in_subfolders[@]} -gt 0 ] ; then
    # do your magic renaming here
  fi
done

没有在这里为您重命名,因为我不确定如何处理多个发现,但是

mv -- "${file}" "${matches_in_subfolders[0]}${file#*.}"

将重命名file为包含它的第一个文件夹的名称及其最长的扩展名(如果不是.waldo,但是.foo.waldo,我假设您想要charlie.foo.waldo,而不仅仅是charlie.waldo)。

相关内容