Исключить один шаблон из совпадения глобуса

54

У меня есть несколько файлов с одним и тем же базовым именем файла. Я хотел бы удалить все, кроме одного

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

Если бы мне не нужно было держать один, я знаю, что мог бы использовать rm foo.*.

TLDP демонстрирует ^отрицание соответствия. Методом проб и ошибок я смог найти

rm foo.*[^org]

делает то, что мне нужно, но я не совсем понимаю синтаксис.

Кроме того, хотя это не ограничение в моем случае использования, я думаю, что этот шаблон также игнорирует foo.oи foo.or. Как работает этот шаблон, и как будет выглядеть только игнорируемый foo.orgглобус?

Джейк
источник
1
В качестве дополнения к ответу @glen стоит упомянуть, что rm foo.*[^org]удаляются все файлы, последний символ которых не является ни одним o, rили g, таким образом, foo.fooтоже не будет совпадать.
Джимми
Вы используете Regular Expression. Вы должны быть осторожны с вашими группировками персонажей. Используя скобки, вы указали класс символов, что означает, что вы будете удалять любые файлы, которые имеют расширение с буквами o, rили gв любом порядке. Используйте скобки, чтобы создать группу и сохранить порядок символов.
Мистер Маскаро,
3
@ jbarker2160 - это не совсем регулярное выражение, его чаще называют глобом (или шаблоном имени файла ), который является более или менее подмножеством регулярного выражения - подробности смотрите в разделе соответствия шаблонов на man-странице bash. Его шаблон foo.*[^org]будет соответствовать любому имени файла, которое начинается с foo.одного или нескольких символов после точки, где последний символ не является o, r или g. Так что будет соответствовать foo.orb, но не foo.orgили foo.orили foo.o. Ответ GlennJackman показывает, как включить расширенные функции сопоставления с образцом, чтобы отменить совпадение.
Джонни

Ответы:

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

Это "фу". с последующим ничего не "орг"

ссылка: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching

Гленн Джекман
источник
Я пытался сделать то же самое, но с помощью скобок и, видимо, при использовании скобок это не работает
Donato
4
Каков синтаксис для сопоставления нескольких имен файлов? скажем, я хочу исключить .org, .png, .txt?
Фридо
@ Свобода @()для списка шаблонов: stackoverflow.com/a/217208/3779853
phil294
23

В Bash вы также можете использовать GLOBIGNORE="*.org"; rm -i foo*.

И unset GLOBIGNOREкогда это будет сделано.

Это на самом деле не лучше shopt -s extglob, но мне легче запомнить.

mivk
источник
5
@Ruslan Это не работает. Вы должны сделать( GLOBIGNORE="*.org"; rm -i foo* )
DBedrenko
3
Обратите внимание, если вы хотите расширить список игнорируемых, GLOBIGNORE="*foo*:*bar*"
отделив их
7

А трубу можно сделать?

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

(очевидно, вы можете заменить echo на rm в последней цепочке).

саман
источник
Полезно при необходимости всего в одной строке.
bruceskyaus
1
Проще запомнить (для меня это часто бывает) и позволяет загружать более сложную обработку :)
drevicko
1
ls -1должно быть более надежным, чтобы все файлы обрабатывались grepотдельно
MichaelChirico,
-1

ОП был очень близок:

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

хотя в этом случае нет *необходимости.

MrMas
источник
это не удастся удалить foo.ortиfoo.erg
Адам Кац