Exclui todos os arquivos, mas maiores, do tipo específico

4

Estou tentando organizar a arte do álbum em minha coleção de músicas para que apenas uma imagem seja atribuída a cada pasta.

Atualmente, minha estrutura de diretórios se parece com:

/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  

(mais outras imagens de baixa resolução geradas pelo Windows media player)

Eu gostaria de examinar cada pasta e excluir todos, exceto o maior jpg, e renomeá-lo para cover.jpg .

Como as tags indicam, eu tenho o cygwin instalado, mas também posso inicializar no Ubuntu onde eu tenho acesso ao bash e zsh, se isso torna o problema mais fácil.

    
por jClark94 18.03.2013 / 20:34

3 respostas

5

No zsh (que você pode usar no Cygwin ou Linux), você pode usar os qualificadores para escolher o maior arquivo. Esse é o maior arquivo por tamanho de byte, não em termos de dimensões de imagem - o que provavelmente é a coisa certa aqui, já que privilegia imagens de alta resolução.

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

O loop percorre todos os subdiretórios de /path/to/music recursivamente. O sufixo (/) restringe as correspondências aos diretórios. O argumento para rm -f usa três qualificadores de glob: oL para classificar por tamanho; [1,-2] para reter apenas as correspondências até a penúltima ( PATTERN([-1]) é a última correspondência, PATTERN([-2]) é a penúltima reunião e PATTERN([1,-2]) é a lista de correspondências da primeira ao penúltimo inclusive); e N para produzir uma lista vazia em vez de deixar o padrão não expandido ou relatar um erro se o padrão não corresponder a nenhum arquivo.

Você pode receber um erro inofensivo se o arquivo restante já for chamado de cover.jpg ou se não houver nenhum arquivo .jpg em um diretório. Para evitá-los, altere a chamada mv para

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

Aqui está um método alternativo que renomeia primeiro e exclui. Ele usa a sintaxe PATTERN1~PATTERN2 , que requer a opção extended_glob , para selecionar arquivos que correspondam a PATTERN1 , mas não PATTERN2 . ((#jpgs)) testa se a matriz jpgs contém pelo menos um elemento.

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
    
por 19.03.2013 / 01:37
3

Aqui está uma Transformação de Schwartzian para você:

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

Use stat para exibir o tamanho e o nome do arquivo, classificar, remover o campo de tamanho, ignorar o maior e iterar os arquivos resultantes.

    
por 18.03.2013 / 22:00
0

Usando o GNU find.

#!/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
#!/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%pre%%f%pre%' | {
            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/
%f%pre%' | { 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/
    
por 20.03.2013 / 04:41

Tags