Jak wyświetlić wszystkie pliki w katalogu oprócz tych z określonymi rozszerzeniami?

28

Załóżmy, że mam folder zawierający .txt , .pdf i inne pliki. Chciałbym wymienić „inne” pliki (tzn. Pliki, które nie mają rozszerzeń .txt lub .pdf ). Czy masz jakieś porady, jak to zrobić?

Wiem, jak wyświetlić listę plików bez danego rozszerzenia. Na przykład, jeśli chcę wyświetlić listę wszystkich plików oprócz plików .txt , to albo

find -not -iname "*.txt"

lub

ls | grep -v '\.txt$' | column

wydaje się działać. Ale jak mogę wyświetlić wszystko oprócz plików .txt lub .pdf ? Wydaje się, że muszę użyć jakiegoś logicznego „lub” w findlub grep.

Andrzej
źródło
2
Pamiętaj, że zachowanie lsvs findvs globowanie może się różnić w przypadku ukrytych plików dot.
jw013,
1
Kolejna rzecz, o której należy pamiętać: findbędzie przechodzić przez podkatalogi, jak rekurencyjny ls. Użyj -maxdepth 1z, findaby uzyskać bardziej podobne zachowanie ls.
jw013,
Więc nie ma rekurencyjnego, wystarczy wymienić pliki w bieżącym katalogu?
stokrotka

Odpowiedzi:

28

Zakładając, że ktoś ma odpowiednią wersję ls, jest to prawdopodobnie najprostszy sposób:

ls -I "*.txt" -I "*.pdf"

Jeśli chcesz iterować we wszystkich podkatalogach:

ls -I "*.txt" -I "*.pdf" -R
Dejian
źródło
8
lsOpcje GNU nie są przenośne.
bahamat
4
lstak naprawdę nie należy do przenośnych skryptów, więc zakładam, że OP pyta tylko o interaktywne użycie.
jw013,
1
Dlaczego ls nie jest przenośny? Czego więc powinienem użyć?
Freedo,
28

Znajdź wsparcie -o

find . ! '(' -name '*.txt' -o -name '*.pdf' ')'

Potrzebujesz nawiasu, aby mieć pierwszeństwo. Znajdź robi wiele rzeczy; Proponuję przeczytać na stronie podręcznika.

Możesz także wykonać wejście lub wejście grep(ale tak naprawdę nie powinieneś analizować danych wyjściowychls )

ls | grep -Ev '\.(txt|pdf)$' | column
derobert
źródło
1
Dzięki! Dlaczego nie powinienem analizować wyniku ls?
Andrew
6
@Andrew pierwszy, ponieważ jest delikatny (rozważ nazwę pliku z nową linią - tak, to poprawna nazwa pliku - znajdź -print0 / -exec / -delete / itp. Uniknij tego problemu); po drugie, ponieważ zwykle jest łatwiejszy sposób.
derobert
Oprócz findstrony polecam z całego serca artykuły Unix Power Tools na temat find, takie jak docstore.mik.ua/orelly/unix3/upt/ch09_06.htm i docstore.mik.ua/orelly/unix3/upt/ch09_12.htm
Wildcard
Tylko po to, aby pomóc rozszyfrować oświadczenie dla ludzi:find . NOT ( *.txt OR *.pdf )
wisbucky
12

Przy bashrozszerzonym globowaniu (włącz za pomocą shopt -s extglob) glob !(*.txt|*.pdf)powinien działać. Możesz przekazać ten glob bezpośrednio do dowolnego polecenia pobierającego argumenty pliku, w tym między innymi ls.

jw013
źródło
1
+1, ale jeśli masz podkatalogi, ich zawartość również będzie na liście; użyj, -daby tego uniknąć:ls -d !(*.txt|*.pdf)
legends2k
Dziękuję, szukałem dokładnie składni, aby zaakceptować wiele plików, dobrze by to pasowało tutaj stackoverflow.com/questions/216995/…
Freedo
6

W zshz extendedglob:

print -rl -- *~*.(txt|pdf)

lub

print -rl -- ^*.(txt|pdf)

Lub z kshglob(tak, to znaczy ksh globbing, a nie „bash Extended globbing”):

print -rl -- !(*.txt|*.pdf)

Pamiętaj jednak, że wykluczają one również pliki kropek.

ksh93 ma FIGNORE(błędną) funkcję:

FIGNORE='@(.|..|*.txt|*.pdf)'
printf '%s\n' *
Thor
źródło
4
find /path/to/directory '!' -name '*.pdf' '!' -name '*.txt'

Jest to równoważne z poleceniem z operatorem OR, ze względu na prawa De Morgana .

Francesco Turco
źródło
3

Jak sugeruje derobert, najlepszym rozwiązaniem jest użycie find. Jednak może w rzeczywistości wykorzystać wynik w rurociągu z innych komend.

GNU (i niektóre BSD) findobsługują -print0predykat, który nakazuje wydrukować nazwę pliku zakończoną znakiem NUL , który to znak nie jest dozwolony w nazwie pliku i gwarantuje, że nie dojdzie do kolizji. Innym poleceniom można polecić użycie NUL jako ogranicznika wejściowego.

Najważniejszym z nich jest GNU xargs, który uruchamia określone polecenie i przekazuje mu listę plików jako argumenty wiersza poleceń. Chcesz uruchomić xargs -r0w połączeniu z find na -print0przykład:

find . -type f ! \( -name \*.pdf -o -name \*.txt \) -print0 | xargs -r0 ls -ld

Spowoduje to bezpieczne wydrukowanie długiej listy katalogów wszystkich plików pdf i txt , w tym tych ze spacją lub niezadrukowanymi znakami w nazwie.

Możesz go również używać z GNU tarw następujący sposób:

tar -zcf myarchive.tar.gz --null --files-from <(
  find . -type f ! -name \*.tar.gz -print0)

To buduje plik tar.gz wszystkich plików, których nazwy nie kończą się na .tar.gz

rsyncakceptuje również pliki rozdzielane zerami z -0parametrem, podobnie jak kilka innych. Ale xargsjest to klej, którego zwykle używasz do tego rodzaju celów. Albo to, albo findjest -execfunkcja.

tylerl
źródło
tarPrzykład komenda jest dobry. Jednak dla większości celów -execjest to lepsze dopasowanie.
Wildcard,
1

Jeśli nie masz podkatalogu

ls !(*.pdf|*.txt)

powinien również działać!

Ale

ls -I "*.pdf" -I "*.txt"

jest powszechnym sposobem.

abu_bua
źródło
0

Jako uzupełnienie, jeśli używasz powłoki kompatybilnej z bash, możesz użyć zmiennej GLOBIGNORE, aby wykluczyć zmiany z dopasowania wzorca. Od mężczyzny:

   GLOBIGNORE
          A colon-separated list of patterns defining the set of filenames
          to be ignored by pathname expansion.  If a filename matched by a
          pathname  expansion  pattern also matches one of the patterns in
          GLOBIGNORE, it is removed from the list of matches.

W twoim konkretnym przypadku:

sh$ (GLOBIGNORE='*.pdf:*.txt'; ls -d *)

Uwaga: uruchamiam to polecenie jako podpowłokę (używając nawiasu), aby nie zmieniać zmiennej środowiskowej GLOBIGNORE mojej interaktywnej powłoki.

Sylvain Leroux
źródło