1

I have many video files that are split by Day, Camera Channel, Event time range (YYYY-MM-DD/VIDEOCHANNELNUMBER-EVENTIMERANGE.mp4)

/2021-07-03/ch2_main_20210703074010_20210703074154.mp4
/2021-07-03/ch2_main_20210703074156_20210703074357.mp4
/2021-07-03/ch2_main_20210703074446_20210703074537.mp4
/2021-07-03/ch2_main_20210703074618_20210703075119.mp4
/2021-07-03/ch2_main_20210703075153_20210703075312.mp4
/2021-07-03/ch2_main_20210703075337_20210703080422.mp4

I want to merge these clips by Day and Camera Channel only (ie /2021-04-03-CH1.mp4)

My process is:

  1. Iterate through each date folder (for VIDEODIR in */)
  2. Within each folder, iterate through each channel number (for VIDEOCHANNELNUMBER in 1 2 3 4 5 6; do)
  3. for each channel number, find all the video files to combine (for f in $VIDEODIR/ch$VIDEOCHANNELNUMBER*.mp4 ; do)
  4. FFMPEG combine and save this file into the root directory (ffmpeg -i $VIDEOLIST -c copy "$DATE-CH$VIDEOCHANNELNUMBER.mp4")
  5. When successful delete the directory of all the original clips. (if [ $? -eq 0 ]; then rm $VIDEODIR -r fi)

I'm stuck because Step 2 errors out when there are no matches due to that video channel being offline during that day for some reason. (zsh: no matches found: /2021-07-03/ch1*.mp4). This breaks the entire loop, rather than skip and continue.

1 Answers1

2

You use the N glob qualifier to say that you want a glob to expand to nothing rather than return an error when there's no match, and the / qualifier to select files of type directory.

You typically want to use the N qualifier when assigning to an array variable:

dirs=( *(N/) )

or when looping¹:

for dir in *(N/)

So, I'm not exactly clear as to what you want to do, but that could look like:

for dir in *(N/); do
  for (( channel = 1; channel <= 6; channel++ )); do
    files=( $dir/ch${channel}_*.mp4(N) )
    if (( $#files )); then
      ffmpeg ... $file
    fi
  done
done

Here, you may be able to take a different approach that loops over all the files at once:

typeset -A list=()
for file (<1900-2100>-<1-12>-<1-31>/ch<1-6>_*.mp4(Nn))
  files[$file:h-${${file:t}%%_*}.mp4]+=$file$'\0'

for output_file (${(k)list}) ffmpeg -i ${(0)list[$output_file]} -c copy $output_file && rm -f ${(0)list[$output_file]}

(and rmdir <1900-2100>-<1-12>-<1-31>(/^F) to remove the empty dirs afterwards).


¹ Anecdotally, that's what the fish does: its globs error out when there's no match like in zsh except when the globs are used with for, set (to assign to variables) or count.