Corrigido. O problema é que $! é expandido cedo demais. Então, fugir atrasou a expansão
su - $USER -c "nohup java $rest_api_opts -jar $app_home/$app_name \
> /dev/null 2>&1& echo \$! > $PID"
O arquivo PID para esta declaração é criado, mas está sempre vazio. Ao executar o shell com -x, vejo que $! vazio, mas no final o trabalho java é deixado em execução no plano de fundo, como desejado. Por que o pid está faltando?
su - $USER -c "nohup java $rest_api_opts -jar $app_home/$app_name \
> /dev/null 2>&1& echo $! > $PID"