Você deve usar -exec aqui:
find . \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' \) \
-exec sh -cf 'IFS=._
for f do d=${f%/*} f=${f##*/}
[ -n "${f##*_*}" ] && continue
set -- $f
printf "%s\n" "mv \" "$d/$f \" "$d/$*"
done' find.rename.shc {} +
Como escrito, isso só imprime o comando que será executado se você prosseguir com ele. Por exemplo, a execução do acima no meu diretório .../media/Videos imprime alguns dos itens a seguir:
mv \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure_Time.s05e37.The_Box_Prince.mp4 \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure.Time.s05e37.The.Box.Prince.mp4
mv \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure_Time.s05e38.Red_Starved.mp4 \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure.Time.s05e38.Red.Starved.mp4
Para prosseguir, você precisa mudar:
...
set -- $f
printf "%s\n" "mv \" "$d/$f \" "$d/$*"
...
... para apenas ...
...
set -- $f; mv "$d/$f" "$d/$*"
...
Em geral, você deve evitar passar nomes de arquivos e similares sobre um pipe, porque quando você faz isso, você perde os delimitadores na cabeça e cauda do nome do arquivo - ele deixa de ser um argumento e se torna uma sequência de bytes em um fluxo . A opção -exec para find permite reter esses delimitadores em um processo filho do processo find em execução. Com + , ele age como xargs - executando o processo filho especificado apenas com a frequência necessária para evitar uma condição ARGMAX .
Em relação ao problema sed , você pode tentar:
LC_ALL=C xargs sed ...
Isso deve pelo menos evitar xargs interpretando a declaração de variável de ambiente como um argumento. Não irá ajudá-lo a editar qualquer nome de arquivo, no entanto.
Uma última nota - o problema mencionado geralmente é causado por uma sequência incompleta de vários bytes ocorrendo no espaço padrão. POSIX especifica que . não pode corresponder a parte de um caractere - e assim .* perde seu significado naquele contexto. Forçar o C locale deve resolvê-lo - mas outra opção para limpar espaços padrão / hold com um% GNUsed é o comando z .