O status passado para exit() por um processo é mascarado para um único byte, por isso está limitado ao intervalo [0-255] . Veja a documentação sobre exit :
The value of status may be 0, EXIT_SUCCESS, EXIT_FAILURE, or any other value, though only the least significant 8 bits (that is, status & 0377) shall be available to a waiting parent process.
Em duas implementações de complemento, -1234d == 0x...ffffb2e e 0x2e == 46d , o resultado esperado é esperado.
Para sua segunda pergunta, você if statement está testando o status de saída de echo $? , não o do seu programa python.
Tente:
python val.py
rc=$?
echo $rc
if [ $rc == 46 ] ; then
...