Из скрипта bash запускается подпроцесс (запуск программы на Python) и создаётся конвейер от него к скрипту bash.
После выхода бэш-скрипта больше нет никакого процесса, в котором труба открыта для чтения. Поэтому в следующий раз, когда Python-скрипт что-нибудь напишет на трубу, он получит сигнал SIGPIPE и умрёт. Вы бы увидели результирующую ошибку, если бы перенаправили только стандартный вывод на трубу, а не стандартную ошибку.
Даже если сценарий на Python проигнорирует сигнал SIGPIPE, он все равно умрет при записи в трубу, потому что запись в трубу будет неудачной, что вызовет исключение.
Если вы хотите видеть только строку, которая говорит вам, что сервер готов, или до строки о первом запросе, то простой способ - это держать читатель запущенным:
exec 3< <(python3 -u -m http.server 2>&1 )
{ while true; do
…
done;
exec cat;
} <&3
Вы можете захотеть перенаправить стандартную ошибку куда-нибудь в лог-файл, вместо того, чтобы блаженно игнорировать сообщения об ошибках.
Альтернативным подходом было бы написать несколько строк на Python, переопределив метод BaseHTTPRequestHandler.log_request
только для того, чтобы выдать запись в лог только в первый раз.