Aviso: eu digitei a maioria desses comandos diretamente no meu navegador. Leitor de advertências.
Com zsh e zmv :
zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'
Explicação: O padrão **/*
corresponde a todos os arquivos nos subdiretórios do diretório atual, recursivamente (ele não corresponde aos arquivos no diretório atual, mas eles não precisam ser renomeados). Os dois primeiros pares de parênteses são grupos que podem ser referenciados como $1
e $2
no texto de substituição. O par final de parênteses adiciona o D
qualificador de glob para que os arquivos de pontos não sejam omitido. -o -i
significa passar a opção -i
para mv
, para que você seja questionado se um arquivo existente seria sobrescrito.
Com apenas ferramentas POSIX:
find . -depth -exec sh -c '
for source; do
case $source in ./*/*)
target="$(printf %sz "${source#./}" | tr / -)";
mv -i -- "$source" "${target%z}";;
esac
done
' _ {} +
Explicação: A instrução case
omite o diretório atual e os subdiretórios de nível superior do diretório atual. target
contém o nome do arquivo de origem ( $0
) com o primeiro ./
removido e todas as barras substituídas por traços, além de um% finalz
. O z
final está lá, caso o nome do arquivo termine com uma nova linha: caso contrário, a substituição do comando o removerá.
Se o seu find
não suporta -exec … +
(OpenBSD, estou olhando para você):
find . -depth -exec sh -c '
case $0 in ./*/*)
target="$(printf %sz "${0#./}" | tr / -)";
mv -i -- "$0" "${target%z}";;
esac
' {} \;
Com bash (ou ksh93), você não precisa chamar um comando externo para substituir as barras por traços, você pode usar a expansão de parâmetro ksh93 com a construção de substituição de string ${VAR//STRING/REPLACEMENT}
:
find . -depth -exec bash -c '
for source; do
case $source in ./*/*)
source=${source#./}
target="${source//\//-}";
mv -i -- "$source" "$target";;
esac
done
' _ {} +