Як перерахувати всі файли в каталозі, окрім файлів із заданими розширеннями?


28

Припустимо, у мене є папка, що містить .txt , .pdf та інші файли. Я хотів би перерахувати "інші" файли (тобто файли, що не мають розширення .txt або .pdf ). Чи є у вас поради, як це зробити?

Я знаю, як перелічити файли, що не мають заданого розширення. Наприклад, якщо я хочу перерахувати всі файли, крім файлів .txt , то будь-який

find -not -iname "*.txt"

або

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

здається, працює. Але як я можу перерахувати всі, крім файлів .txt або .pdf ? Здається, мені потрібно використовувати якесь логічне "чи" в findабо grep.


2
Майте на увазі, що поведінка lsvs findvs globing може відрізнятися для прихованих точкових файлів.
jw013

1
Ще одна річ, яку слід пам’ятати: findбуде переміщуватися підкаталогами, як рекурсивна ls. Використання -maxdepth 1з , findщоб змусити його поводитися як ls.
jw013

Так що ніяких рекурсивних, просто перерахуйте файли в поточному режимі?
ромашка

Відповіді:


28

Якщо припустимо, що у них є відповідна версія ls, це, можливо, найпростіший спосіб:

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

Якщо ви хочете повторити всі підкаталоги:

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

8
lsПараметри GNU не є портативними.
Багамат

4
lsНасправді не належить до портативних сценаріїв, тому я припускаю, що ОП запитує лише про інтерактивне використання.
jw013

1
Чому ls не є портативним? Що я повинен використовувати тоді?
Фредо

28

Знайдіть опори -o

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

Вам потрібні дужки, щоб правильно зробити пріоритет. Знайти робить багато чого; Я пропоную прочитати його сторінку.

Ви також можете зробити або в grep(але насправді ви не повинні аналізувати вихідls )

ls | grep -Ev '\.(txt|pdf)$' | column

1
Спасибі! Чому я не повинен проаналізувати вихід ls?
Андрій

6
@Andrew спочатку, тому що його крихке (врахуйте ім'я файлу з новим рядком у ньому - так, це дійсне ім'я файлу - знайдіть -print0 / -exec / -delete / тощо. Уникайте цієї проблеми); по-друге, тому що зазвичай існує простіший спосіб.
derobert

На додаток до сторінки find, я щиро рекомендую статті про електронні інструменти Unix find, такі як docstore.mik.ua/orelly/unix3/upt/ch09_06.htm та docstore.mik.ua/orelly/unix3/upt/ch09_12.htm
Wildcard

Просто для розшифровки твердження для людей:find . NOT ( *.txt OR *.pdf )
wisbucky

12

При bashрозширеному глобулі (увімкніть shopt -s extglob) глобус !(*.txt|*.pdf)повинен працювати. Ви можете передати цей глобус безпосередньо до будь-якої команди, яка бере аргументи файлів, включаючи, але не обмежуючись ними ls.


1
+1, але якщо у вас є підкаталоги, їхній вміст також буде вказаний; використовуйте, -dщоб уникнути цього:ls -d !(*.txt|*.pdf)
legends2k

Спасибі, я шукав саме для синтаксису приймати кілька файлів, це підходить добре б тут stackoverflow.com/questions/216995 / ...
Freedo

6

В zshз extendedglob:

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

або

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

Або з kshglob(так, тобто ksh globbing не "bash Extended globbing"):

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

Пам'ятайте, що вони також виключають крапкові файли.

ksh93 має FIGNORE(mis) функцію:

FIGNORE='@(.|..|*.txt|*.pdf)'
printf '%s\n' *


3

Як пропонує Derobert, найкраще скористатись вашою пропозицією find. Однак ви можете фактично використовувати результат у конвеєрі з іншими командами.

GNU (та деякі BSD) findпідтримують -print0предикат, який вказує йому на друк імені файлу, закінченого символом NUL , який не заборонений у назві файлу, і гарантує, що не буде зіткнення. Інші команди можуть бути доручені використовувати NUL як їх вхідний роздільник.

Найважливіший з них - GNU xargs, який виконує вказану команду і передає їй список файлів у вигляді аргументів командного рядка. Ви хочете запустити xargs -r0спільно з Find's, -print0наприклад:

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

Це безпечно друкує довгий каталог з переліком усіх файлів pdf та txt , включаючи файли з пробілами або недрукованими символами в імені.

Ви також можете використовувати його з GNU tarнаступним чином:

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

Це створює файл tar.gz усіх файлів, імена яких не закінчуються на .tar.gz

rsyncтакож приймає файли з обмеженим значенням з -0параметром, як і кілька інших. Але xargsце клей, який ви зазвичай використовуєте для цього типу. Або це , або find«s -execособливість.


Приклад tarкоманд - хороший. Однак для більшості цілей -execце краще підходить.
Wildcard

1

Якщо у вас немає підкаталогу

ls !(*.pdf|*.txt)

також повинен працювати!

Але

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

є загальним способом.


0

Як доповнення, якщо ви використовуєте сумісну з bash оболонку, ви можете використовувати змінну GLOBIGNORE для виключення відновлення з відповідності шаблонів. Від людини:

   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.

У вашому конкретному випадку:

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

Будь ласка, зауважте, що я запускаю цю команду як підрозділ (використовуючи дужки), щоб не змінити змінну середовища GLOBIGNORE моєї інтерактивної оболонки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.