Gostaria apenas de usar um loop bash para isso:
for i in **/*.txt; do mkdir "${i%.txt}"; done
Se eu executar isso no seu exemplo, obtenho:
$ tree
.
├── 1
│ └── 01-01-2015.txt
├── 2
│ └── 02-02-2016.txt
└── 3
└── 03-03-2017.txt
3 directories, 3 files
$ shopt -s globstar
$ for i in **/*.txt; do mkdir "${i%.txt}"; done
terdon@oregano foo $ tree
.
├── 1
│ ├── 01-01-2015
│ └── 01-01-2015.txt
├── 2
│ ├── 02-02-2016
│ └── 02-02-2016.txt
└── 3
├── 03-03-2017
└── 03-03-2017.txt
6 directories, 3 files
globstar
é uma opção bash, explicada em man bash
:
globstar
If set, the pattern
**
used in a pathname expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a/
, only directories and subdirectories match.
Assim, após habilitá-lo com shopt -s globstar
, o padrão **/*.txt
encontrará todos os arquivos (ou dirs) cujo nome termina com .txt
.
O ${i%.txt}
é a sintaxe da shell para remover uma substring. O formato geral é ${variable%string}
e removerá a primeira instância de string
do final da variável. Portanto, ${i%.txt}"
será o nome do arquivo (incluindo diretórios pai), menos o .txt
. Portanto, [passá-lo para mkdir
criará o diretório desejado.
Pessoalmente, acho a sintaxe acima muito mais simples, mas veja como fazer isso com find
:
find . -name '*.txt' -exec sh -c 'mkdir ${0%.txt}' {} \;
Aqui, o -exec command {}
substituirá {}
por cada um dos resultados de find
e, em seguida, executará command
nele. Como o comando aqui é uma chamada para sh -c
, o sh
assumirá o {}
como seu parâmetro posicional zero, $0
. Então, nós executamos a mesma substituição de shell conforme explicado acima para criar o diretório.