Use find :
find -maxdepth 1 ! -name "*.c" -print0 | xargs -0 ...
Observe que -maxdepth , -print0 , -r e -0 são encontrados em algumas implementações de find (foram introduzidos pelo GNU find / xargs ), mas não são especificados pelo POSIX. Outra maneira é, como Stéphane mencionou em seu comentário, usar a ação -exec de find - lembre-se de usar a forma -exec command {} + , pois reduz drasticamente o número de invocações de command (tem que permitir sintaxe onde os nomes dos arquivos são colocados no final, ou então você precisa colocar o command dentro de uma chamada sh -c ).
Como alternativa, grep a saída de ls
ls | grep -v "\.c$" | xargs ...
Você pode filtrar várias extensões com expressões regulares:
... | grep -v "\.\(c\|md\)$" | ...
com regexps prolongados:
... | grep -Ev "\.(c|md)$" | ...
com a opção de strings fixas (não coincide apenas com o final do nome do arquivo!):
... | grep -vF ".c
.md" | ...
ou encadeando mais grep s:
... | grep -v "\.c$" | grep -v "\.md$" | ...
Dito isso, find é provavelmente a melhor opção, já que com a opção -print0 ele manipula todos os caracteres possíveis em nomes de arquivos que podem precisar ser salvos de outra forma (contanto que find e xargs consigam trabalhar com NULL -terminadas cadeias de caracteres - por exemplo, as ferramentas GNU são).