Wyklucz jeden wzór z dopasowania globalnego


53

Mam kilka plików o tej samej podstawowej nazwie pliku. Chciałbym usunąć wszystkie oprócz jednego

foo.org #keep
foo.tex #delete
foo.fls #delete
foo.bib #delete
etc

Gdybym nie musiał go mieć, wiem, że mógłbym go użyć rm foo.*.

TLDP demonstruje ^zanegowanie dopasowania. Dzięki próbom i błędom udało mi się to znaleźć

rm foo.*[^org]

robi to, czego potrzebuję, ale tak naprawdę nie rozumiem składni.

Ponadto, chociaż nie jest to ograniczenie w moim przypadku użycia, myślę, że ten wzór również ignoruje foo.oi foo.or. Jak działa ten wzorzec i jak wyglądałby glob ignorujący tylko foo.org ?


1
Jako dodatek do @glen odpowiedzieć warto wspomnieć, że rm foo.*[^org]usuwa wszystkie pliki, których ostatnia postać jest ani o, ralbo g, więc foo.foonie pasuje albo.
jimmij

Używasz Regular Expression. Powinieneś uważać na swoje postacie grupujące. Za pomocą wsporników już podano klasy znaków sens, że chcesz usunąć wszystkie pliki, które miały rozszerzenie z literami o, ralbo gw dowolnej kolejności. Użyj nawiasu, aby utworzyć grupę i zachować kolejność znaków.
Pan Mascaro

3
@ jbarker2160 - to nie jest tak naprawdę wyrażenie regularne, częściej nazywane jest glob (lub wzorzec nazwy pliku ), który jest mniej więcej podzbiorem wyrażenia regularnego - zobacz sekcję dotyczącą dopasowania wzorca strony podręcznika bash, aby uzyskać szczegółowe informacje. Jego wzorzec foo.*[^org]będzie pasował do każdej nazwy pliku, która zaczyna się foo.od jednego lub więcej znaków po kropce, gdzie ostatnim znakiem nie jest o, r lub g. Tak by pasowało foo.orb, ale nie foo.orglub foo.orlub foo.o. Odpowiedź GlennJackman pokazuje, jak włączyć funkcje rozszerzonego dopasowywania wzorca, aby negować dopasowanie.
Johnny

Odpowiedzi:


52
shopt -s extglob
echo rm foo.!(org)

To jest „foo”. po którym następuje coś NIE „org”

ref: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching


Próbowałem zrobić to samo, ale z nawiasami i najwyraźniej przy użyciu nawiasów nie działa
Donato

4
Jaka jest składnia pasująca do wielu nazw plików? powiedz, że chcę wykluczyć .org, .png, .txt?
Freedo,

@ Freedo @()dla listy wzorców: stackoverflow.com/a/217208/3779853
phil294

23

W bash możesz także użyć GLOBIGNORE="*.org"; rm -i foo*.

A unset GLOBIGNOREkiedy skończone.

To nie jest tak naprawdę lepsze niż shopt -s extglob, ale łatwiej mi zapamiętać.


5
@ Ruslan To nie działa. Powinieneś to zrobić( GLOBIGNORE="*.org"; rm -i foo* )
DBedrenko,

3
Uwaga: jeśli chcesz rozwinąć listę ignorowanych, oddziel je dwukropkiem, np.GLOBIGNORE="*foo*:*bar*"
phyatt

7

Rura może zrobić?

ls * | grep -v "foo.org" | xargs -I {} echo {}

(oczywiście możesz chcieć zastąpić echo rm w ostatnim łańcuchu).


Przydatne w razie potrzeby w jednym wierszu.
bruceskyaus

1
Łatwiejsze do zapamiętania (dla mnie często to robię) i pozwala na bardziej skomplikowane przetwarzanie do uruchomienia :)
drevicko

1
ls -1powinien być bardziej niezawodny, aby mieć pewność, że wszystkie pliki są obsługiwane greposobno
MichaelChirico

0

OP był bardzo blisko:

rm foo.*[^o][^r][^g]

choć w tym przypadku nie *jest to konieczne.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.