Pesquisa recursiva e movimentação de um sistema de arquivos

1

Eu tenho um sistema de arquivos que gostaria de organizar em ordem alfabética. É grande e fazer manualmente levaria uma vida inteira.

O que eu gostaria de saber é se seria possível escrever algo no terminal que criaria as pastas A-Z e depois fazer o terminal pesquisar todo o sistema de arquivos e mover todas as subpastas para a respectiva pasta de letras.

Também gostaria que a pesquisa fosse organizada com base na extensão de arquivo encontrada na subpasta.

por exemplo, localize e mova todas as subpastas começando com a letra A contendo a extensão de arquivo .doc para folderA.

Obrigado antecipadamente

    
por Johnny 06.02.2017 / 19:44

1 resposta

2

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 por find -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> entre then e fi 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 que find é 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 o grep -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
    
por Byte Commander 06.02.2017 / 21:15