Digamos que eu tenha vários arquivos em um diretório
filename-1.ext1
filename-1.ext2
filename-1.ext3
filename-2.ext1
filename-2.ext2
filename-2.ext3
filename-3.ext1
filename-3.ext2
filename-3.ext3
Quero então criar subdiretórios no mesmo diretório com o mesmo nome dos arquivos (nome do arquivo, mas sem ramal) e movê-los assim
filename-1
├──filename-1.ext1
├──filename-1.ext2
└──filename-1.ext3
filename-2
├──filename-2.ext1
├──filename-2.ext2
└──filename-2.ext3
filename-3
├──filename-3.ext1
├──filename-3.ext2
└──filename-3.ext3
Qual seria a maneira mais eficiente de conseguir isso?
Editar: ext1, ext2, ext3 servem apenas para indicar três nomes de arquivos distintos, como .foo, .bar, .top, .coffee etc.
Responder1
Como você está usando zsh
, isso poderia ser feito assim:
for name (*.ext<->(.)) mkdir -p -- $name:r && mv -- $name $name:r
ou usando a forma longa mais familiar do for
loop,
for name in *.ext<->(.); do
mkdir -p -- $name:r &&
mv -- $name $name:r
done
Isso itera sobre todos os arquivos regulares que correspondem ao padrão *.ext<->
onde <->
corresponde a qualquer número. É o qualificador glob (.)
que impõe a correspondência apenas de arquivos regulares. Altere todo o padrão para *.*(.)
se desejar corresponder ao nome de arquivo de qualquer arquivo normal que contenha um ponto; exigimos que o ponto esteja presente, pois você deseja remover uma extensão de nome de arquivo posteriormente. Para usar um padrão mais rígido em vez de mais flexível, use algo como filename-<->.ext<->(.)
. Esse padrão exige que você saiba que deseja corresponder nomes que começam com string filename-
.
A $name:r
expansão resultará no mesmo valor de $name
, mas sem a extensão (ou seja, apenas a "raiz" do valor).
Usamos --
para sinalizar o fim das opções para ambos mkdir
e mv
para evitar que nomes que começam com um travessão sejam confundidos com opções.
Responder2
Com zmv
:
autoload -Uz zmv # best in ~/.zshrc
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -P mkmv -n '(*).ext<->(#q.)' '$1/$f'
(remova -n
quando estiver satisfeito).
Dessa forma, você se beneficia das zmv
verificações de integridade do.
Responder3
Use este for
loop que é compatível com os shells bash e zsh:
for file in *.*; do
[ -f "$file" ] &&
mkdir -p -- "${file%.*}" &&
mv -- "$file" "${file%.*}/"
done
-p
opçãomkdir
garante que o arquivo exista, o erro não foi gerado%.*
retira a extensão dos nomes dos arquivos.
Responder4
Com o GNU paralelo (uma ferramenta que estou começando a perceber o poder):
ls | parallel 'mkdir -p {.}; mv -i {} {.}'
Como isso não está vinculado à CPU de forma alguma, acho que parallel
não trará nenhuma vantagem de velocidade, mas ainda é mais curto do que muitas das outras soluções fornecidas.
E isso não depende do padrão de nomes de arquivos.