Jak mogę usunąć ponumerowane pliki z danego zakresu?

16

Mam folderAkilka plików z sekwencją numerów zaczynającą się od a_000000. Chcę usunąć pliki zaczynające się od określonej liczby: powiedzmy a_000750do końca plików w tym folderA. Czy ktoś mógłby doradzić, jak to zrobić za pomocą skryptu powłoki?

Tak
źródło
Czy mogę założyć, że wszystkie te nazwy plików mają 6-cyfrowe sufiksy?
muru
tak, są :) zaczynają się od 000000 do pewnej liczby
Tak
5
rm a_000[89]* a_0007[5-9]*?
Rinzwind
@Rinzwind, czy mógłbyś wyjaśnić to polecenie?
Tak
2
@ użytkownik 1460166 a_000[89]*obejmuje każdy plik rozpoczynający się od a_0008lub a_0009, i a_0007[5-9]*obejmuje każdy plik rozpoczynający się od, a_0007a następnie zawierający liczbę między 5 a 9, a po nim cokolwiek.
muru

Odpowiedzi:

35

Zakładając, że znasz lub możesz odgadnąć koniec zakresu, możesz użyć rozszerzeń nawiasów :

rm a_{000750..000850}

Powyższe spowoduje usunięcie 101 plików między a_000750 i a_000850 włącznie (i narzeka na nazwy plików, które odnoszą się do nieistniejących plików). Jeśli masz na to zbyt wiele plików, użyj find:

find . -name 'a_*' | while read file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Tutaj po findprostu wyświetla listę wszystkich pasujących plików a_*. Lista jest przekazywana do whilepętli, w której każda nazwa pliku jest wczytywana do zmiennej $file. Następnie, używając funkcji manipulacji ciągiem bash , jeśli część numeryczna (znajdź drukuje pliki jako ./file, więc ${file#./a_}drukuje tylko liczbę) jest 000750większa lub większa, plik jest usuwany. -vJest właśnie tam, dzięki czemu można zobaczyć, jakie pliki zostały usunięte.

Zauważ, że powyższe zakłada rozsądne nazwy plików. Jeśli twoje imiona mogą zawierać spacje, znaki nowej linii lub inne dziwne znaki, użyj tego:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done
terdon
źródło
Po co unikać [[?
muru
1
@muru po co go używać? [[nie upraszcza tu [[ "${file#./a_}" > 000749 ]]na przykład rzeczy , nie czyni go nawet krótszym. Nie lubię używać niepotrzebnej składni, a ta będzie działać nawet w prostszych powłokach, takich jak dash.
terdon
Ponieważ [[lepiej radzi sobie ze spacjami i dziwnościami (nie dbam o to zbytnio >).
muru
1
@muru tak, ale [jest w porządku, jeśli cytujesz zmienną tak jak ja, działa na znacznie większej liczbie powłok i jest prostsza.
terdon
Jeśli nalegasz. Nie mój problem.
muru
3

Możesz zrobić coś takiego:

find . -regextype posix-extended -iregex './a_[0-9]{6}' -execdir bash -c '[[ ${1##./a_} > 000750 ]] && echo $1' "removing: " {} \;

Lub:

find . -regextype posix-extended -iregex './a_[0-9]{6}' | sort | sed '0,/000750/d' | xargs echo

Pierwsza metoda zakłada stały prefiks, usuwa go i sprawdza wartość.

Druga metoda zakłada sufiks o stałej długości (i wspólny stały prefiks) i opiera się na tym fakcie; i choć w leksykografii 201jest wcześniej 31, to nie jest wcześniej 031.

Sprawdź to za pomocą echo polecenia, a gdy będziesz już pewien, że zawiera listę poprawnych plików, użyj rmzamiast tego.

muru
źródło
żaden z nich nie działa: /
Tak
@ user1460166 ah, prawdopodobnie wynika to z dopasowania wyrażenia regularnego. Zaktualizuję to.
muru
wciąż nie działa. btw, pliki są w formacie .png :)
Tak
@ user1460166 czy możesz powiedzieć, jak to nie działa?
muru
Otwieram terminal, cd do folderu, następnie kopiuję linię i wklejam, ale pliki nie są usuwane
Tak
0

Rozwiązanie powłoki POSIX

Pierwsze rozwiązanie terdona opiera się na rozszerzaniu nawiasów klamrowych, które jest właściwością bashi kshnie można go jednak używać w standardowej /bin/shpowłoce, do której Ubuntu jest dowiązane symbolicznie /bin/dash.

W przypadkach, w których musisz polegać /bin/shna przenośności swoich skryptów, istnieją dwa sposoby na rozwiązanie tego problemu. Jednym byłoby globbing. Właśnie cd folderAi stamtąd biegnij rm a_*. Innym sposobem byłoby zaimplementowanie alternatywnego użycia pętli w stylu C.while <CONDITION>;do ...done w języku powłoki i sformatowanie liczb za pomocą printf:

$ sh -c 'i=0;while [ $i -le 750 ]; do filename=$(printf "a_%06d" $i);echo "$filename";i=$((i+1)) ;done'

Zauważ, że tutaj używam echo. wymienić echo "$filename"zrm ./"$filename" lub rm -- "$filename"kiedy jesteś gotowy, aby usunąć pliki. Należy również pamiętać, że należy to zrobić, gdy już cdedytujesz żądany katalog.

(ab) za pomocą awk

Awk, który jest przyjemnym językiem podobnym do C, może nam pomóc na dwa sposoby: (1) możemy wygenerować nazwy plików za pomocą pętli for i sformatować je za pomocą sprintffunkcji oraz (2) usunąć te pliki za pomocą system()polecenia, które przekaże wygenerowaną nazwę pliku i rmpolecenie do /bin/sh:

awk 'BEGIN{for(i=0;i<=750;i++){filename=sprintf("a_%06d",i);system("rm "filename);} }'

Perl

Kontynuując pomysł przenośnego podejścia, w którym „generujemy” nazwy plików, możemy zrobić to samo w Perlu:

perl -le 'for(0..750){$fd=sprintf("a_%06d",$_);unlink($fd)}'
Sergiy Kolodyazhnyy
źródło
0

Tak prosty jak

rm partialfilename* -f

W twoim przykładzie to jest

rm a_00075* -f
Witalij Dubyna
źródło
1
Przykro mi to mówić, ale to nie jest zakres, to wszystkie pliki zaczynające się od a_00075...
Fabby
1
* jest symbolem wieloznacznym, OP szuka odpowiedzi na pytanie, jak usunąć ZAKRES rzeczy ... np. jeśli masz pliki od 1 do 100 i chcesz usunąć # 41 do # 75
Joshua Besneatte