Wyrażanie regularne w celu dopasowania nazwy pliku

2

Mam skrypt, który wyświetla listę plików spełniających określone kryteria. Wyświetla tylko nazwy plików i jest niepotrzebny fragment tekstu.

Przykładowy ciąg to:

[gg]_Magi_-_13_[DB38165F].mkv

To, co chciałbym osiągnąć w wyniku, to:

[gg]_Magi_-_13

Udało mi się zastąpić podkreślenia, ale nie udało mi się pomyślnie przyciąć pliku [CRC32] .mkv. Ograniczam też liczbę znaków i umieszczam wielokropek na końcu, jeśli rozciągają się one ponad 28 znaków, ale nawet jeśli nie przekracza 28 znaków, nadal dołącza wielokropek na końcu.
Kodem tego jest:

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

Pomoc w jednym z tych problemów byłaby bardzo mile widziana.

użytkownik181353
źródło
Jakiego języka używasz? Czy wszystkie nazwy plików są w tym formacie?
Aluísio ASG,
@ Aluísio ASG - Przekazuję wszystko przez skrypt bash. Większość, jeśli nie wszystkie nazwy plików mają ten format.
user181353,
@DW Czy używałeś kiedyś menedżera plików o nazwie Ranger? Pozwala na masową zmianę nazw plików przy użyciu Vima (co, jak być może wiesz, pozwala na edycję bloków w pionie). Uważam, że w rzeczywistości bardzo skomplikowana zmiana nazwy jest bardzo łatwa (zwykle wymaga tylko kilku prostych zmian). github.com/hut/ranger
@OP Właśnie zauważyłem problem z twoim problemem. Jeśli skrócisz wszystkie nazwy plików do 28 znaków za pomocą wielokropka, i masz kilka plików o długości 32 znaków, których licznik ma więcej niż 28 znaków, zmienisz nazwy plików na tę samą nazwę pliku i skończysz na jednym pliku. Np. [blahblah] blahblahblahblahblah 01I [blahblah] blahblahblahblahblah 02oba stają się [blahblah] blahblahblahblahb...(już nie różnymi plikami)

Odpowiedzi:

1

Myślę, że najkrótszym rozwiązaniem spełniającym wszystkie kryteria jest właśnie to

awk '{
    if (match($0, "^(.*)_[^_]+$", a)) {
        print substr(a[1], 1, 27) (length(a[1]) > 27 ? "..." : "")
    }
}'
sparkie
źródło
Zrobią bashto również dwie linie czystego , co jest prawdopodobnie jeszcze krótsze, nie mówiąc już o szybszym. Zobacz moją odpowiedź .
kopischke
1
sed -e 's/_\[.*\.mkv//' -e 's/^\(.\{28\}\).*/\1.../' file.txt

Pierwszy bit usuwa paski _[blah].mkv, a drugi bit drukuje pierwsze 28 znaków i umieszcza je ...na końcu - ale jeśli ciąg znaków ma mniej niż 28 znaków, drukuje tylko nazwę pozbawionego pliku, bez dodawania elips.

Jeśli rozszerzenie pliku nie zawsze będzie oznaczać * .mkv, możesz użyć tego (w sed, $oznacza „do końca linii”):

sed -e 's/_\[.*$//' -e 's/^\(.\{28\}\).*/\1.../' file.txt
zła
źródło
Dobry, ale zawsze znajduję sedodrobinę przesady w przypadku tak całkiem podstawowej manipulacji ciągiem. Zobacz moją odpowiedź dla dwóch linii czystych, bashktóre osiągają ten sam wynik.
kopischke
1

Chociaż awk, seda firma ma swoje zalety, nie są one potrzebne do tego. Możesz łatwo osiągnąć wszystko, o co prosiłeś, używając tylko bashoperacji na łańcuchach i dopasowywania wzorców. Zakładając, że przypisałeś nazwę pliku do $name:

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

odetnie typ pliku i CRC w nawiasach $name. Jeśli chcesz mieć 100% pewność, że odetniesz tylko CRC, możesz użyć rozszerzonego wyrażenia regularnego zamiast powyższego:

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

Obcinanie nazw dłuższych niż 28 znaków jest następnie osiągane przez:

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

- dwa wiersze bashłącznie (nie licząc logiki, pętli lub innych, aby uzyskać nazwy plików do var i kod wyjściowy, oczywiście), bez zewnętrznych elementów. Główną zaletą jest to, że kod błyskawicznie płonie, ponieważ powłoka nigdy nie musi uruchamiać zewnętrznych plików binarnych.

kopischke
źródło
OK, to naprawdę miłe. Zdecydowanie najlepsza odpowiedź tutaj.
evilsoup
0

Wypróbuj tę funkcję bash (ostrzeżenie: nie testowano):

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+)$/\1/')"
    if (( ${#r} < 28 )); then
        # Outputs $r
        echo "$r"
    else
        # Outputs the first 27 characters from $r followed by an ellipsis
        echo "${r::27}…"
    fi
}
Aluísio ASG
źródło
0

Nie najczystsze rozwiązanie, ale możesz to zrobić:

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

EDYCJA: Meh, podrap tę odpowiedź. Nie da ci elipsy.


źródło