删除特定类型的除最大文件之外的所有文件

删除特定类型的除最大文件之外的所有文件

我正在尝试组织音乐收藏中的专辑封面,以便每个文件夹只分配一张图像。

我的目录结构目前如下所示:

/path/to/music/Album Name/
/path/to/music/Album Name/1 - Track one.flac
...
/path/to/music/Album Name/cover.jpg (either this)
/path/to/music/Album Name/folder.jpg (or this)
/path/to/music/Album Name/Album Name.jpg (or this is the largest file)
/path/to/music/Album Name/AlbumArtSmall.jpg  

(加上 Windows 媒体播放器生成的其他低分辨率图像)

我想扫描每个文件夹并删除除最大的 jpg 之外的所有文件夹并将其重命名为cover.jpg.

正如标签所示,我安装了 cygwin,但也可以启动到 Ubuntu,在那里我可以访问 bash 和 zsh,如果这会使问题变得更容易的话。

答案1

在 zsh(您可以从 Cygwin 或 Linux 中使用)中,您可以使用全局限定符选择最大的文件。这是按字节大小计算的最大文件,而不是按图像尺寸计算 - 这可能是正确的,因为它优先考虑高分辨率图像。

for d in /path/to/music/**/*(/); do
  rm -f $d/*.jpg(oL[1,-2]N)
  mv $d/*.jpg $d/cover.jpg
done

循环递归遍历所有子目录/path/to/music。后缀(/)将匹配限制为目录。rm -f使用三个 glob 限定符的参数:oL按大小排序;[1,-2]仅保留倒数第二个之前的匹配(PATTERN([-1])是最后一个匹配、PATTERN([-2])是倒数第二个匹配、是PATTERN([1,-2])从第一个到倒数第二个(包括第一个和倒数第二个)的匹配列表);并N生成一个空列表,而不是让模式不展开或在模式与文件不匹配时报告错误。

如果剩余文件已被调用或者目录中cover.jpg没有文件,您可能会收到无害的错误。.jpg为了避免它们,请将mv调用更改为

[[ -e $d/cover.jpg ]] || mv $d/*.jpg $d/cover.jpg

这是先重命名然后删除的替代方法。它使用PATTERN1~PATTERN2需要extended_glob选项的语法来选择匹配PATTERN1但不匹配的文件PATTERN2((#jpgs))测试jpgs数组是否至少包含一个元素。

setopt extended_glob
for d in /path/to/music/**/*(/); do
  jpgs=($d/*.jpg(oL))
  ((#jpgs)) || continue
  [[ $jpgs[1] == */cover.jpg ]] || mv $jpgs[1] $d/cover.jpg
  rm -f $jpgs[2,-1]
done

答案2

这是一个施瓦茨变换为你:

stat -c "%s %n" *.jpg | sort -n | cut -d " " -f 2- | head -n -1 |
while IFS= read -r filename; do echo rm "$filename"; done

用于stat输出大小和文件名、排序、删除大小字段、忽略最大的字段并迭代结果文件。

答案3

使用 GNU 查找。

#!/usr/bin/env bash
# GNU find + bash4 / ksh93v / zsh
# Get the largest file matching pattern in the given directories recursively
${ZSH_VERSION+false} || emulate ksh
${BASH_VERSION+shopt -s lastpipe extglob}

function getLargest {
    typeset -A cur top || return
    typeset dir x
    for dir in "$2"/*/; do
        [[ -d $dir ]] || return 0
        getLargest "$1" "${dir%/}" || return
        top[size]=-1
        find "$dir" -maxdepth 1 -type f -name "$1" -printf '%s\0%f\0' | {
            while :; do
                for x in cur\[{size,name}\]; do
                    IFS= read -rd '' "$x" || break 2
                done
                if (( cur[size] > top[size] )); then
                    top[size]=${cur[size]} top[name]=${cur[name]}
                fi
            done
            mv -- "${dir}"{"${top[name]}",cover.jpg}
            rm -f -- "${dir}"!(cover.jpg)
        }
    done
}

# main pattern dir [ dir ... ]
function main {
if [[ -n $1 ]]; then
    typeset dir pattern=$1
    shift
    for dir; do
        [[ -d $dir ]] || return
            getLargest "$pattern" "$dir"
        done
    else
        return 1
    fi
}

main \*.jpg /path/to/music/

相关内容