Consegui corrigir o problema relacionado a links simbólicos em portage.txt executando o seguinte comando:
equery files '*' | while read i; do readlink -e "${i}"; done | sort | uniq \
> portage.txt
Isso serve para colocar em portage.txt os arquivos que os links simbólicos apontam, e não os próprios links simbólicos. Isso é necessário porque o comando find que cria all.txt não lista nenhum link simbólico, mas apenas os arquivos para os quais eles apontam, portanto, haveria muitos falsos positivos. É um comando muito lento, pois ele executa readlink em milhares de arquivos, mas não consegui encontrar uma solução melhor. Qualquer sugestão é bem vinda.
Outra coisa que eu entendi (isso foi mais fácil) é porque portage.txt era maior que all.txt . Isso se deve principalmente ao fato de eu explicitamente ter podado o diretório /usr/src e todos os arquivos abaixo dos resultados do comando find , mas equery os listou independentemente.
A última coisa que fiz, mesmo que não estivesse na questão, foi ignorar coisas do Python (principalmente __pycache__ files e arquivos com o sufixo .pyc ou .pyo ):
grep '\(\.cpython-32\)\?\.py[co]$\|/__pycache__' candidates.txt \
> candidates-bytecode.txt
sed -e 's/\(\.cpython-32\)\?\.py[co]$/.py/' \
-e 's/\/__pycache__//' \
candidates-bytecode.txt | sort | uniq \
> candidates-bytecode-source.txt
comm -23 candidates-bytecode-source.txt portage.txt \
> orphaned-bytecode.txt
Desta forma eu rastrear a origem de todas as coisas do Python e verificar se está em portage.txt . Como você pode ver, escrevi a mesma expressão regular duas vezes, uma para o comando grep e a outra para o comando sed , mas talvez isso possa ser feito em apenas uma única etapa.