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.