Se você não se importar em dividir o arquivo com base na categoria e trabalhar com as partes, poderá fazer isso:
split -l 500 -a 3 infile
rnd=( $(printf %s\n x??? | shuf -n 100) )
cat "${rnd[@]}" > rand1
rm "${rnd[@]}"
cat x??? > rand2
rm x???
Este split s o arquivo em 200 partes de 500 linhas cada (uma única peça por categoria) e seleciona 100 peças aleatórias via shuf - os nomes de arquivos são salvos em uma matriz - rnd . Em seguida, mescla as partes listadas na matriz em rand1 , exclui-as e mescla as partes restantes em rand2 e as exclui também. Esta solução assume que as linhas em seu arquivo estão agrupadas por categoria e que os únicos nomes de arquivos que correspondem a x??? no diretório atual são aqueles produzidos pelo comando split .