fix: stop child processes from eating the script on stdin #8

Merged
nugget merged 1 commit from fix/child-processes-steal-stdin into main 2026-08-22 23:22:05 -05:00
Collaborator

ffmpeg, ffprobe, mkvpropedit and makemkvcon all read standard input, and a subprocess inherits the parent's. When these scripts are driven from a shell heredoc the script is stdin, so a child that consumes a few bytes deletes them from commands not yet read.

The failure surfaces on a later line and looks nothing like its cause. A loop over disc titles produced:

bash: line 14: rab: command not found

because ffmpeg inside audio_identify.py had swallowed the leading g of the next grab call. That title was silently never processed. Re-running by hand always works, since an interactive shell is not a heredoc — so it reads as intermittent.

Changes

  • stdin=subprocess.DEVNULL at all 22 call sites, including the makemkvcon rip in rip_disc.py (longest-running child, and the one whose silent skip is hardest to spot).
  • README entry under Things that have burned us.
  • audio_identify.py: note that MakeMKV's stream flags outrank these measurements where a scan log exists. A TrueHD/DD pair measured r=0.983 against the 0.985 companion cut and was reported as an alternate mix, while the scan said the TrueHD had HasCoreAudio and the DD had CoreAudio|DerivedStream. The null did not break the tie either — core and two known dubs all landed within 0.2 dB.

Verification

  • syntax + --help gate from AGENTS.md: all pass
  • regression against real media: three tools driven from one heredoc, all following commands survived intact (previously the second was corrupted)
`ffmpeg`, `ffprobe`, `mkvpropedit` and `makemkvcon` all read standard input, and a subprocess inherits the parent's. When these scripts are driven from a shell heredoc the script *is* stdin, so a child that consumes a few bytes deletes them from commands not yet read. The failure surfaces on a later line and looks nothing like its cause. A loop over disc titles produced: ``` bash: line 14: rab: command not found ``` because ffmpeg inside `audio_identify.py` had swallowed the leading `g` of the next `grab` call. That title was silently never processed. Re-running by hand always works, since an interactive shell is not a heredoc — so it reads as intermittent. ## Changes - `stdin=subprocess.DEVNULL` at all 22 call sites, including the `makemkvcon` rip in `rip_disc.py` (longest-running child, and the one whose silent skip is hardest to spot). - README entry under *Things that have burned us*. - `audio_identify.py`: note that MakeMKV's stream flags outrank these measurements where a scan log exists. A TrueHD/DD pair measured **r=0.983** against the 0.985 companion cut and was reported as an alternate mix, while the scan said the TrueHD had `HasCoreAudio` and the DD had `CoreAudio|DerivedStream`. The null did not break the tie either — core and two known dubs all landed within 0.2 dB. ## Verification - syntax + `--help` gate from AGENTS.md: all pass - regression against real media: three tools driven from one heredoc, all following commands survived intact (previously the second was corrupted)
ffmpeg, ffprobe, mkvpropedit and makemkvcon all read standard input, and a
subprocess inherits the parent's. When these scripts are driven from a shell
heredoc the script itself is stdin, so a child that consumes a few bytes
deletes them from commands that have not been read yet.

The failure lands on a later line and hides its cause. Driving a loop over
disc titles produced

    bash: line 14: rab: command not found

because ffmpeg inside audio_identify.py had swallowed the leading `g` of the
next `grab` call; that title was then never processed, with no error anywhere
near the tool that caused it. Re-running by hand always works, because an
interactive shell is not a heredoc, which makes it look intermittent.

Pass stdin=subprocess.DEVNULL at all 22 call sites, including the makemkvcon
rip in rip_disc.py, which is both the longest-running child and the one whose
silent title skip is hardest to notice.

Also record in audio_identify.py that MakeMKV's stream flags outrank these
measurements where a scan log exists. A TrueHD/DD pair measured r=0.983
against the 0.985 companion cut and was reported as an alternate mix, while
the scan said outright that the TrueHD had HasCoreAudio and the DD had
CoreAudio|DerivedStream. The phase-inversion null did not break the tie
either: the core and two known dubs all nulled within 0.2 dB.
nugget merged commit 1c55e84fe5 into main 2026-08-22 23:22:04 -05:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
nugget/media-import-tooling!8
No description provided.