Existe a seguinte estrutura de arquivos:
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
Gostaria de renomear todos os arquivos da pasta raiz, neste caso this-file.waldo
e another-file.waldo
. Se em alguma subpasta existir um arquivo com o mesmo nome base de um arquivo .waldo, eu gostaria de renomear o arquivo .waldo usando o nome da subpasta que contém o homônimo da seguinte forma:
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
O arquivo deverá ser renomeado se e somente se uma subpasta tiver um arquivo que compartilhe o mesmo nome base e deverá ser renomeado com o mesmo nome da subpasta.
Qual seria a maneira mais eficiente de conseguir isso?
- Sempre haverá um arquivo .waldo presente.
- Se não houver nenhum arquivo que compartilhe o nome base, ele deverá simplesmente ignorar e passar para o próximo até encontrar uma correspondência.
- Os nomes de arquivos são nomes de arquivos normais do sistema operacional, então sim, pode haver &()[]# etc.
Responder1
Isso poderia ser algo como:
for f (*.waldo(N)) (){ (($#)) && echo mv -- $f $1:h.waldo; } */$f:r.*(NY1)
(remova o echo
(ensaio) se estiver satisfeito).
Alguns dos recursos menos usuais do zsh encontrados lá:
for f (values) action
: forma abreviada do loop for (semelhante à sintaxe perl)() { body; } args
: função anônima$var:r
:r
oot name (parte sem extensão, como em csh/vim...)$var:h
:h
ead (nome do diretório, como em csh/vim)(N)
:N
qualificador ullglob glob: para que não relate um erro se não houver correspondência:(Y1)
: pare após a primeira partida de qualificação global.
Responder2
Primeiro, você obtém uma lista de todos os arquivos no diretório atual
files=(*(.DoN))
então, você faz algo com cada um deles:
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
Não mudei o nome para você aqui porque não tenho certeza de como lidar com várias descobertas, mas
mv -- "${file}" "${matches_in_subfolders[0]}${file#*.}"
renomearia file
para o nome da primeira pasta que o contém e a extensão mais longa que ela tinha (se não for .waldo
, mas .foo.waldo
, presumo que você queira charlie.foo.waldo
, não apenas charlie.waldo
).