Obtendo regex para corresponder a um nome de arquivo

2

Eu tenho um script que lista vários arquivos que correspondem a um determinado critério. Ele produz apenas nomes de arquivos e há um monte de texto desnecessário.

Uma string de exemplo é:

[gg]_Magi_-_13_[DB38165F].mkv

O que eu gostaria de alcançar na saída é:

[gg]_Magi_-_13

Eu pude substituir os sublinhados, mas não tive sorte em cortar o [CRC32] .mkv com sucesso. Além disso, limito o número de caracteres e coloco reticências no final, se eles ultrapassarem 28 caracteres, mas, mesmo que não ultrapasse 28 caracteres, ele ainda acrescenta as reticências no final.
O código para isso é:

print substr( $0, 0, 28 )"[…]"}

Ajuda sobre qualquer um desses problemas seria muito apreciada.

    
por user181353 07.01.2013 / 00:47

5 respostas

2

Acho que a solução mais curta para atender a todos os critérios é esse

awk '{
    if (match($0, "^(.*)_[^_]+$", a)) {
        print substr(a[1], 1, 27) (length(a[1]) > 27 ? "..." : "")
    }
}'
    
por 07.01.2013 / 04:59
1
sed -e 's/_\[.*\.mkv//' -e 's/^\(.\{28\}\).*/.../' file.txt

O primeiro bit retira o _[blah].mkv , e o segundo bit imprime os primeiros 28 caracteres e coloca o ... no final - mas se a string tiver menos de 28 caracteres, ele apenas imprime o nome do arquivo removido. sem adicionar as elipses.

Se a extensão do arquivo não for sempre * .mkv, você pode usar isso (em sed, $ significa 'até o final da linha'):

sed -e 's/_\[.*$//' -e 's/^\(.\{28\}\).*/.../' file.txt
    
por 29.01.2013 / 12:33
1

Embora awk , sed e empresa tenham seus méritos, eles não são necessários para isso. Você pode facilmente obter tudo o que solicitou usando apenas bash de operações de sequência e correspondência de padrões. Supondo que você tenha atribuído o nome do seu arquivo a $name :

name="${name%_\[*\].*}"

cortará o tipo de arquivo e o CRC entre parênteses de $name . Se você precisa ter 100% de certeza de que apenas corta os CRCs, você pode usar um regex estendido em vez do acima:

[[ $name =~ (.*)_\[[[:xdigit:]]{8}\]\..*$ ]] && name="${BASH_REMATCH[1]}"

O truncamento de nomes com mais de 28 caracteres é então obtido por:

(( ${#name} > 28 )) && name="${name::27}…"

- duas linhas de bash total (sem contar a lógica, loop ou outro, para obter seus nomes de arquivos no var, e o código de saída, é claro), sem externos. A principal vantagem é que o código é muito rápido, já que o shell nunca precisa executar binários externos.

    
por 29.01.2013 / 18:39
0

Tente esta função bash (aviso: não testado):

function convert_filename {
    # Regex guide:
    #   ^(.*)_?                everything since the beginning of the string,
    #                          optionally followed by an underscore
    #   \[[a-fA-F0-9]{8}\]    8 hexadecimal characters, surrounded by []
    #   \.(.\w+)$              filename extension at the end of the string
    local r="$(echo "$1" | sed -r 's/^(.*)_?\[[a-fA-F0-9]{8}\]\.(.\w+)$//')"
    if (( ${#r} < 28 )); then
        # Outputs $r
        echo "$r"
    else
        # Outputs the first 27 characters from $r followed by an ellipsis
        echo "${r::27}…"
    fi
}
    
por 07.01.2013 / 01:24
0

Não é a solução mais limpa, mas você pode fazer isso:

 echo "[gg]_Magi_-_13_[DB38165F].mkv" | awk -F '_' '{print $1"_"$2"_"$3"_"$4}'

EDIT: Meh, risque esta resposta. Não vai te dar a elipse.

    
por 07.01.2013 / 01:21

Tags