Исключить из * в командной строке

Существует множество ситуаций, когда использование * практически неизбежно, например, rm -rf * в папке, содержащей тысячи вложенных папок и файлов.

Но что, если вы хотите исключить только один или два файла или папки из команды rm? Я гуглил свой путь и нашел только довольно сложные решения, такие как find . -depth -not \( -name 'one' -o -name 'two' \ -o -name 'three' \) -exec rm {} \;, как указано здесь .

Есть ли возможность сделать это более простым способом - без этого обхода find? Например. rm -rf --exclude='one' --exclude='two' --exclude='three' * как в rsync или просто rm -rf -e 'one','two','three' *?

Может быть, даже общая возможность исключить вещи из * (поэтому другие команды, такие как cp, mv, ... не имеют реализовать самостоятельно)? Что-то вроде *{'one','two','three'} или около того?

14
задан 6 August 2013 в 12:39

3 ответа

Для Bash существует опция оболочки под названием extglob, которая по умолчанию деактивирована , чтобы сохранить совместимость со стандартным синтаксисом оболочки. Extglob дополняет синтаксис дополнительными операторами, такими как !(), ?(), @() и некоторыми другими.

Чтобы включить extglob, введите shopt -s extglob. Чтобы оставить его включенным для текущего типа пользователя echo 'shopt -s extglob' >> ~/.bashrc.

Например, с помощью extglob вы можете использовать

rm -rf !(one|two|three)
.
0
ответ дан 6 August 2013 в 12:39

Я построил за исключением именно для этого (извините, что я еще не смог добавить документацию).

Если у вас есть папка, подобная следующей:

$ ls
a b c d

Набрав except b d, вы получите a и c

$ except b d
ac

Теперь вы можете передать это rm.

except b d | xargs -0 rm

Это может быть трудно запомнить, так почему бы просто не создать скрипт поверх исключений, называемых rm-except:

#!/usr/bin/env bash

except "$@" | xargs -0 rm

Аналогично легко это ls-except:

[ 114]
0
ответ дан 6 August 2013 в 12:39

В качестве альтернативы extglob (хотя это очень хороший ответ, и каждый должен иметь shopt -s extglob globstar в своем .bashrc), вы можете использовать глобальную переменную $ GLOBIGNORE . Допустим, вы хотите получить все файлы, кроме 'foo.txt' и 'bar baz.txt':

GLOBIGNORE=foo.txt:'bar baz.txt'

... однако, это включит параметр оболочки dotglob, что означает, что * будет сопоставлять файлы, начинающиеся с точки (которые обычно скрыты). Таким образом, вам на самом деле нужны две команды:

GLOBIGNORE=foo.txt:'bar baz.txt'
shopt -u dotglob

Поскольку это глобальная переменная, она будет влиять на каждый глобус, который вы используете, до тех пор, пока $ GLOBSTAR не будет сброшен при выходе или с помощью

GLOBIGNORE=

Он также будет работать только с литеральными строками, переданными в переменную. Вы можете понять, что я имею в виду, установив $ GLOBIGNORE и посмотрев на разницу между этими командами:

printf '%s\n' *
printf '%s\n' ./*
0
ответ дан 6 August 2013 в 12:39

Другие вопросы по тегам:

Похожие вопросы: