Como outras respostas já foram identificadas, ${f%.*} é expandido pelo shell antes de executar o comando xargs . Você precisa que essa expansão aconteça uma vez para cada nome de arquivo, com a variável de shell f definida para o nome do arquivo (passando -I f não faz isso: xargs não tem noção de variável shell, ele procura pela string f no comando, por isso, se você usou, por exemplo, xargs -I e echo … , teria executado comandos como ./somedir/somefile.wmacho .mp3 ).
Mantendo essa abordagem, informe xargs para invocar um shell que possa executar a expansão. Melhor, diga que find - xargs é uma ferramenta amplamente obsoleta e é difícil de usar corretamente, já que as versões modernas do find possuem uma construção que faz o mesmo trabalho (e mais) com menos dificuldades de encanamento. Em vez de find … -print0 | xargs -0 command … , execute find … -exec command … {} + .
find . -name '*.wma' -type f -exec sh -c 'for f; do echo "${f%.*}.mp3"; done' _ {} +
O argumento _ é $0 no shell; os nomes dos arquivos são passados como argumentos posicionais, em que for f; do … faz um loop. Uma versão mais simples desse comando executa um shell separado para cada arquivo, o que é equivalente, mas um pouco mais lento:
find . -name '*.wma' -type f -exec sh -c 'echo "${0%.*}.mp3"' {} \;
Você não precisa usar find aqui, presumindo que esteja executando um shell razoavelmente recente (ksh93, bash ≥4.0 ou zsh). No bash, coloque shopt -s globstar no seu .bashrc para ativar o padrão **/ glob para recursar em subdiretórios (em ksh, que é set -o globstar ). Então você pode correr
for f in **/*.wma; do
echo "${f%.*}.mp3"
done
(Se você tiver diretórios chamados *.wma , adicione [ -f "$f" ] || continue no início do loop).