Home Looping over all files of certain extension in a directory
Reply: 1

Looping over all files of certain extension in a directory

menteith Published in 2018-02-13 16:28:19Z

I wrote a small script that unzips all the *.zip files in the current directory to extract only *.srt files directory to a newly created directory. It then loops over all the *.mkv files in the current directory to get their name and then changes subs/*.srt file name to produce a new file name that is exactly as *.mkv file name. The script works when there is one zip file and one mkv file but when there are more files it produces bad filenames. I cannot track why this is the case. Now I figured out when this is the case.


I managed to narrow down the scenarios when file names are changed in erroneous way. Let's say in a current directory we have three *.mkv files: (sorted alphabetically)

$ ls -1a *.mkv

and three *.srt files:

$ ls -1a *.srt

When I run the script, I get:

subs/Home.S06E10.srt -> subs/Home.S06E10.1080p.BluRay.x264-PRINTER.srt
subs/Home.S06E10.1080p.BluRay.x264-PRINTER.srt -> subs/Home.S06E11.1080p.BluRay.x264-PRINTER.srt
subs/Home.S06E11.1080p.BluRay.x264-PRINTER.srt -> subs/Home.S06E12.1080p.BluRay.x264-PRINTER.srt

As you see, Home.S06E10.srt is used twice

#!/usr/bin/env bash

mkdir -p subs
mkdir -p mkv-out
mkdir -p subs-bak
# unzip files, maybe there are subtitles in it...
for zip in *.zip; do
    if [ -f "$zip" ]; then
        unzip "$zip" -d subs "*.srt" >/dev/null

# move all subtitles to subs catalog
for srt in *.srt; do
    if [ -f "$srt" ]; then
        mv "*.srt" subs


if [ ${#mkvCount[@]} != ${#srtCount[@]} ]; then
    echo "Different number of srt and mkv files!"
    exit 1

for MOVIE in *.mkv; do
    for SUBTITLE in subs/*.srt; do
        NAME=$(basename "$MOVIE" .mkv)
        if [ ! -f "$SRT" ]; then
            echo "$SUBTITLE -> ${SRT}"
            mv "$SUBTITLE" "$SRT"
giusti Reply to 2018-02-13 19:01:30Z

You seem to be relying on the lexicographical order of the files to associate one SRT with one MKV. If all you have are season-episode files for the same series, then I suggest a completely different approach: iterate a season and an episode counters, then generate masks in the form S##E## and find a movie and a subtitle files. If you find them, you move them.

for season in {01..06}; do
  for episode in {01..24}; do
    # Count how many movies and subtitles we have in the form S##E##
    nummovies=$(find -name "*S${season}E${episode}*.mkv" | wc -l)
    numsubs=$(find -name "*S${season}E${episode}*.srt" | wc -l)
    if [[ $nummovies -gt 1 || $numsubs -gt 1 ]]; then
      echo "Multiple movies/subtitles for S${season}E${episode}"
      exit 1

    # Skip if there is no movie or subtitle for this particular
    # season/episode combination
    if [[ $nummovies -eq 0 ]]; then
    if [[ $numsubs -eq 0 ]]; then
      echo "No subtitle for S${season}E${episode}"

    # Now actually take the MKV file, get its basename, then find the
    # SRT file with the same S##E## and move it
    moviename=$(find -name "*S${season}E${episode}*.mkv")
    basename=$(basename -s .mkv "$moviename")
    subfile=$(find -name "*S${season}E${episode}*.srt")
    mv "${subfile}" "${basename}.mkv"

If you don't want to rewrite everything, just change your last loop:

  1. Drop the inner loop
  2. Take the movie name instead and use sed to find the particular S##E## substring
  3. Use find to find one SRT file like in my code
  4. Move it

This has the benefit of not relying on hard-coded number of seasons/episodes. I guessed six seasons and no season with more than 26 episodes. However I thought my code would do and would look more simple.

Make certain that there will be exactly one SRT file. Having zero or more than one file will probably just give an error from mv, but it's better to be safe. In my code I used a separate call to find with wc to count the number of lines, but if you are more knowledgeable in bash-foo, then perhaps there's a way to treat the output of find as an array instead.

In both my suggestions you can also drop that check for # movies = # subtitles. This gives you more flexibility. The subtitles can be in whatever directories you want, but the movies are assumed to the in the CWDIR. With find you can also use the -or operator to accept other extensions, such as AVI and MPG.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.304026 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO