循环遍历目录中某些扩展名的所有文件

时间:2018-02-13 16:28:20

标签: linux bash

我写了一个小脚本,解压缩当前目录中的所有*.zip文件,只将*.srt个文件目录提取到新创建的目录中。然后循环遍历当前目录中的所有*.mkv文件以获取其名称,然后更改subs/*.srt文件名以生成与*.mkv文件名完全相同的新文件名。 当有一个zip文件和一个mkv文件时,该脚本可以工作,但是当有更多文件时,它会产生错误的文件名。 我无法追踪为什么会这样。现在我知道是什么时候。

修改

我设法缩小了以错误方式更改文件名的方案。 假设在当前目录中我们有三个* .mkv文件:(按字母顺序排序)

$ ls -1a *.mkv
Home.S06E10.1080p.BluRay.x264-PRINTER.mkv 
Home.S06E11.1080p.BluRay.x264-PRINTER.mkv
Home.S06E12.1080p.BluRay.x264-PRINTER.mkv

和三个* .srt文件:

$ ls -1a *.srt
Home.S06E10.srt 
Home.S06E11.BDRip.X264-PRINTER.srt 
Home.S06E12.BDRip.X264-PRINTER.srt

当我运行脚本时,我得到:

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

如您所见,Home.S06E10.srt使用了两次

#!/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
    fi
done

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

mkvCount=(*.mkv)
srtCount=(subs/*.srt)

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

for MOVIE in *.mkv; do
    for SUBTITLE in subs/*.srt; do
        NAME=$(basename "$MOVIE" .mkv)
        SRT="subs/$NAME.srt"
        if [ ! -f "$SRT" ]; then
            echo "$SUBTITLE -> ${SRT}"
            mv "$SUBTITLE" "$SRT"
        fi
    done
done

1 个答案:

答案 0 :(得分:1)

您似乎依赖文件的词典顺序将一个SRT与一个MKV相关联。如果您拥有的是同一系列的季节剧集文件,那么我建议采用完全不同的方法:迭代一个季节和一集剧集,然后以S ## E ##的形式生成面具并找到一个电影和一个字幕文件。如果你找到它们,就移动它们。

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
    fi

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

    # 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"
  done
done

如果您不想重写所有内容,只需更改上一个循环:

  1. 放下内循环
  2. 取代电影名称并使用sed查找特定的S ## E ## substring
  3. 使用find查找我的代码中的一个SRT文件
  4. 移动
  5. 这样做的好处是不依赖于硬编码的季节/剧集数量。我猜到了六季,没有超过26集的季节。但是,我认为我的代码会做,看起来会更简单。

    确保只有一个SRT文件。拥有零个或多个文件可能只会从mv给出错误,但最好是安全的。在我的代码中,我使用find单独调用wc来计算行数,但如果你对bash-foo更了解,那么也许有办法处理{{find的输出。 1}}作为数组而不是。

    在我的建议中,您也可以放弃#movies =#subtitles的检查。这为您提供了更大的灵活性字幕可以在您想要的任何目录中,但是电影被假定为CWDIR中的电影。使用find,您还可以使用-or运算符接受其他扩展程序,例如AVI和MPG。