Tente:
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'f=${1#./}; mv "$1" "./${f//\//_}"' None {} \;
Isso é seguro para todos os nomes de arquivos, mesmo aqueles com novas linhas em seus nomes.
Como funciona
-
-mindepth 2
Isto diz para não processar nenhum arquivo que já esteja no diretório atual.
-
-type f -name '*.pdf'
Isso restringe a pesquisa a arquivos regulares com a extensão
pdf
. -
-exec bash -c '...' None {} \;
Isso executa o comando na cadeia entre aspas, fornecendo o nome do arquivo como o primeiro argumento,
$1
.Para nossos objetivos, a string
None
é simplesmente um espaço reservado. Ele é atribuído a$0
, sob as convenções do bash, é o nome do comando que estamos executando. -
f=${1#./}; mv "$1" "./${f//\//_}"
Isso (a) remove o prefixo
./
do nome do arquivo e (b) move o arquivo para o local desejado com o novo nome.${1#./}
é um exemplo de remoção de prefixo do bash . Ele retorna o strign$1
com./
removido do começo.${f//\//_}
é um exemplo de substituição de padrões de bash . Ele retorna a string$f
com todos os/
substituídos por_
. Para ler mais sobre esses recursos, veja a seção emman bash
intitulada Expansão do Parâmetro .
Versão mais eficiente
A versão acima invoca o bash para cada arquivo encontrado. Alternativamente, podemos invocar bash apenas uma vez para vários arquivos encontrados. Para fazer isso, colocamos nosso comando em um for
loop:
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'for f in "$@"; do f=${f#./}; echo mv "$f" "./${f//\//_}"; done' None {} +
Problema alternativo
Suponha que todos os arquivos que desejamos estejam em um diretório de segundo nível e queremos que os arquivos movidos tenham a ordem dos nomes de diretórios invertidos, de modo que, em vez de ./path1_pathA_fileI.pdf
, acabemos com ./pathA_path1_fileI.pdf
. Neste caso:
for d1 in */; do d1=${d1%/}; for d2 in "$d1"/*/; do d2=${d2%/}; p="${d2#$d1/}_$d1"; for f in "./$d2"/*.pdf; do echo mv "$f" "./${p}_${f#./$d2/}"; done; done; done
Ou, para aqueles que preferem seus comandos espalhados por várias linhas:
for d1 in */
do
d1=${d1%/}
for d2 in "$d1"/*/
do
d2=${d2%/}
p="${d2#$d1/}_$d1"
for f in "./$d2"/*.pdf
do
echo mv "$f" "./${p}_${f#./$d2/}"
done
done
done