Você pode usar o comando find
para recursivamente (primeiro em profundidade) mover todas as pastas para uma pasta com o nome da primeira letra do nome do arquivo, criando-a se ainda não existir, começando no diretório de trabalho atual :
find . -depth -mindepth 1 -type d -execdir bash -c 'l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/"' \;
Explicação:
-
find . -depth -mindepth 1 -type d -execdir <COMMAND> \;
procura recursivamente seu diretório atual (.
), primeiro em profundidade (-depth
), para todos os diretórios (-type d
), excluindo o próprio diretório atual (-mindepth 1
).
Então,cd
s no diretório pai de cada pasta encontrada e executa<COMMAND>
, substituindo cada ocorrência de{}
pelo nome do diretório encontrado relativo (-execdir
). -
bash -c '<COMMAND>'
inicia uma subchave Bash e permite interpretar e executar a string<COMMAND>
. Precisamos disso porque vamos usar recursos de shell como variáveis, pipes, substituição de comandos, etc., o que não pode ser feito diretamente porfind -execdir
. -
l=./$(basename "{}" | head -c1)
armazena a primeira letra do nome do diretório encontrado (lembre-se que{}
é substituído pelo resultado da pesquisa) na variável do shell$l
. -
test -d "${l^^}" || mkdir "${l^^}"
verifica se existe um diretório e o cria, se não. O nome do diretório ("${l^^}"
) é o conteúdo da variável$l
(a primeira letra do nome do diretório encontrado) convertido em maiúsculas. -
mv "{}" "${l^^}/"
move o diretório encontrado (lembre-se novamente que{}
é substituído) no diretório nomeado após sua primeira letra convertida em maiúscula ('"$ {l ^^} /", que nós preparamos anteriormente).
Exemplo de execução:
$ tree -F
.
├── apple/
│ ├── hamster/
│ ├── horse/
│ ├── snake/
│ │ ├── blue
│ │ ├── green
│ │ ├── grey
│ │ └── red
│ └── spider/
├── apricot/
├── banana/
├── cherry/
│ ├── pink
│ ├── purple
│ └── yellow
└── coconut/
9 directories, 7 files
$ find . -depth -mindepth 1 -type d -execdir bash -c 'l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/"' \;
$ tree -F
.
├── A/
│ ├── apple/
│ │ ├── H/
│ │ │ ├── hamster/
│ │ │ └── horse/
│ │ └── S/
│ │ ├── snake/
│ │ │ ├── blue
│ │ │ ├── green
│ │ │ ├── grey
│ │ │ └── red
│ │ └── spider/
│ └── apricot/
├── B/
│ └── banana/
└── C/
├── cherry/
│ ├── pink
│ ├── purple
│ └── yellow
└── coconut/
14 directories, 7 files
Editar:
Se você quiser não recursivamente, ou seja, operando apenas nos subdiretórios diretos de primeiro nível de seu diretório de trabalho atual, basta adicionar a opção -maxdepth 1
ao comando find
. Você pode omitir a opção -depth
e depois:
find . -mindepth 1 -maxdepth 1 -type d -execdir bash -c 'l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/"' \;
Editar 2:
É possível executar a movimentação apenas se o diretório a ser movido contiver arquivos correspondentes a um critério específico (aqui: contém um arquivo com o nome do arquivo que termina em .jpg
em qualquer lugar, incluindo subdiretórios), mas adiciona outro comando find
e uma cláusula if
:
find . -depth -mindepth 1 -maxdepth 1 -type d -execdir bash -c 'if find "{}" -type f -iname '*.jpg' | grep -q '.' ; then l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/" ; fi' \;
Explicação (após a edição 2):
-
if <CONDITION> ; then <COMMANDS> ; fi
Verifica o código de saída do comando<CONDITION>
e só executa o<COMMANDS>
entrethen
efi
se a condição foi atendida (código de saída 0).<COMMANDS>
é o mesmo da versão anterior. -
%código%
Pesquisas dentro do diretório encontrado pelo comando
find "{}" -type f -iname '*.jpg' | grep -q '.'
externo (lembre-se mais uma vez quefind
é substituído) por arquivos ({}
) com um nome que termine com-type f
, insensível a maiúsculas e minúsculas (.jpg
). br> O-iname '*.jpg'
simplesmente verifica se ogrep -q '.'
produz qualquer saída no STDOUT (significa que os arquivos foram encontrados) e retorna um código de saída 0, então, 1 se nenhum arquivo foi encontrado.
Exemplo de execução (após a edição 2):
$ tree -F
.
├── apple/
│ ├── hamster/
│ ├── horse/
│ ├── snake/
│ │ ├── blue
│ │ ├── green
│ │ ├── grey
│ │ └── red
│ └── spider/
├── apricot/
├── banana/
│ └── black.jpg
├── cherry/
│ ├── pink
│ ├── purple
│ └── yellow
└── coconut/
9 directories, 8 files
$ find . -depth -mindepth 1 -maxdepth 1 -type d -execdir bash -c 'if find "{}" -type f -iname '*.jpg' | grep -q '.' ; then l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/" ; fi' \;
$ tree -F
.
├── A/
│ └── apple/
│ ├── hamster/
│ ├── horse/
│ │ └── white.jpg
│ ├── snake/
│ │ ├── blue
│ │ ├── green
│ │ ├── grey
│ │ └── red
│ └── spider/
├── apricot/
├── B/
│ └── banana/
│ └── black.jpg
├── cherry/
│ ├── pink
│ ├── purple
│ └── yellow
└── coconut/
11 directories, 9 files