Search code examples
bashfish

Is it possible to group files by some complex logic and then operate them with bash/fish?


I download some videos and some of them are split into several parts:

001 aaaa part1.mp4
001 aaaa part2.mp4
002 bbbb part1.mp4
003 cccc part1.mp4
003 cccc part2.mp4
004 dddd part1.mp4
004 dddd part2.mp4
005 eeee part1.mp4
006 ffff part1.mp4
007 gggg part1.mp4
008 hhhh part1.mp4

In the above files, the 001 ... 003 ... and 004 ... are split files, and others are not, even if they have part1.mp4 in name.

I want to find and combine the split files with some tools, like mp4box.

In order to do this, I need to do:

  1. Group the files by the numbers of each file in the beginning, and the groups which contain more than one file, it's the part files I need. So the 001/003/004 file will be found.

  2. Generate new file name for them by removing the part?.mp4. For 001 aaaa part1.mp4 and 001 aaaa part2.mp4, it will generate 001 aaaa.mp4

  3. Call mp4box -add "001 aaaa part1.mp4" -cat "001 aaaa part2.mp4" "001 aaaa.mp4" to combine them

  4. Repeat this for all the part files

I tried to do this with fish/bash, but failed. In the end, I use some other programming languages to complete, but I still want to know is it possible to do it with fish or bash.


Solution

  • In fish, I'd iterate not over the files but over the numbers, so something like

    for num in (printf '%03d\n' (seq 1 8)) # Pad the numbers to the given length - assuming they are all three digits long
        set -l files $num* # This will generate a list with as many elements as there are matching files, so if there's no file, there's zero elements
        count $files >/dev/null; or continue # Skip numbers that aren't used
        set -l name (string replace -r 'part.' '' -- $files[1]) # Or sed if you are using fish < 2.3
        if test (count $files) -gt 1
            mp4box -add $files[1] -cat $files[2..-1] $name # Assuming all but the last argument after cat are taken to be files to concatenate, otherwise it's a little more complicated
        else
            mv $files $name # If there's one file, just rename it
        end
    end