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,cds 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>entrethenefise 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