Как мне перечислить все файлы в каталоге, кроме файлов с указанными расширениями?

28

Предположим, что у меня есть папка, содержащая .txt , .pdf и другие файлы. Я хотел бы перечислить «другие» файлы (т.е. файлы, не имеющие расширений .txt или .pdf ). Есть ли у вас какие-либо советы, как это сделать?

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

find -not -iname "*.txt"

или

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

похоже на работу. Но как я могу перечислить все, кроме файлов .txt или .pdf ? Кажется, мне нужно использовать какое-то логическое «или» в findили grep.

Эндрю
источник
2
Имейте в виду , что поведение lsпротив findпротив универсализации может отличаться для скрытых составляют скрытые.
jw013
1
Еще одна вещь, которую нужно иметь в виду: findбудут проходить через подкаталоги, как рекурсивные ls. Используйте -maxdepth 1с, findчтобы заставить его вести себя как ls.
jw013
Так что не рекурсивно, просто список файлов в текущем каталоге?
маргаритка

Ответы:

28

Предполагая, что у вас есть подходящая версия ls, это, возможно, самый простой способ:

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

Если вы хотите перебрать все подкаталоги:

ls -I "*.txt" -I "*.pdf" -R
Dejian
источник
8
lsОпции GNU не переносимы.
Багамат
4
lsна самом деле не относится к переносимым скриптам, так что я предполагаю, что OP спрашивает только об интерактивном использовании.
jw013
1
Почему ls не переносимый? Что я должен использовать тогда?
Фридо
28

Найти опоры -o

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

Вам нужно круглые скобки, чтобы сделать правильный приоритет. Find делает много вещей; Я предлагаю прочитать его man-страницу.

Вы также можете сделать или в grep(но на самом деле, вы не должны анализировать выводls )

ls | grep -Ev '\.(txt|pdf)$' | column
derobert
источник
1
Благодарность! Почему я не должен анализировать вывод ls?
Андрей
6
@ Сначала, потому что он хрупкий (рассмотрите имя файла с новой строкой - да, это правильное имя файла - найдите -print0 / -exec / -delete / и т.д., чтобы избежать этой проблемы); во-вторых, потому что обычно есть более простой способ.
Дероберт
В дополнение к справочной страницеfind я искренне рекомендую статьи о Unix Power Tools find, такие как docstore.mik.ua/orelly/unix3/upt/ch09_06.htm и docstore.mik.ua/orelly/unix3/upt/ch09_12.htm
Подстановочный
Просто, чтобы помочь расшифровать утверждение для людей:find . NOT ( *.txt OR *.pdf )
wisbucky
12

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

jw013
источник
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(неправильную) особенность:

FIGNORE='@(.|..|*.txt|*.pdf)'
printf '%s\n' *
Тор
источник
3

По предложению Дероберта, вам лучше всего использовать find. Однако вы можете использовать результат в конвейере с другими командами.

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

Наиболее важным из них является GNU xargs, который запускает указанную вами команду и передает ей список файлов в качестве аргументов командной строки. Вы хотите запустить xargs -r0вместе с find, -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особенность.

tylerl
источник
tarПример команды хороший один. Для большинства целей, тем не менее, -execлучше подходит.
Wildcard
1

Если у вас нет подкаталога

ls !(*.pdf|*.txt)

тоже должно работать!

Но

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

это общий способ.

abu_bua
источник
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 моей интерактивной оболочки.

Сильвен Леру
источник