Como mover todos os arquivos de uma pasta para um subdiretório com o mesmo nome?

Como mover todos os arquivos de uma pasta para um subdiretório com o mesmo nome?

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 forloop,

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:rexpansã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 mkdire mvpara 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 -nquando estiver satisfeito).

Dessa forma, você se beneficia das zmvverificações de integridade do.

Responder3

Use este forloop que é compatível com os shells bash e zsh:

for file in *.*; do
  [ -f "$file" ] &&
    mkdir -p -- "${file%.*}" &&
    mv -- "$file" "${file%.*}/"
done
  • -popção mkdirgarante 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 parallelnã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.

informação relacionada