web-dev-qa-db-ja.com

コマンドラインの*から除外

*の使用が事実上避けられない状況がたくさんあります。 rm -rf *は、数千のサブフォルダーとファイルを保持するフォルダー内にあります。

しかし、rmコマンドから1つまたは2つのファイルまたはフォルダーのみを除外する場合はどうでしょうか。私は自分のやり方をグーグルで調べましたが、 here のように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' *のように?

*から物事を除外する一般的な可能性もあります(したがって、cpmvなどの他のコマンドは、独自に実装する必要はありません)。 *{'one','two','three'}のようなものですか?

14
David

Bashにはextglobというシェルオプションがあります。これは、標準のシェル構文との互換性を保つために デフォルトで非アクティブ化 です。 Extglob は、!()?()@()などの追加演算子によって構文を補完します。

extglobをオンにするには、shopt -s extglobと入力します。現在のユーザーに対して有効にするには、echo 'shopt -s extglob' >> ~/.bashrcと入力します。

Rmの例:extglobでは、次を使用できます。

rm -rf !(one|two|three)
33
choroba

そのために except を作成しました(まだドキュメントを追加できなかったので)。

次のようなフォルダがあります:

$ ls
a b c d

except b dと入力すると、acが表示されます

$ except b d
ac

これで、rmにパイプできます。

except b d | xargs -0 rm

これは覚えにくいかもしれませんので、なぜrm-exceptと呼ばれる例外の上にスクリプトを作成しないのですか:

#!/usr/bin/env bash

except "$@" | xargs -0 rm

ls-exceptも同様に簡単です:

#!/usr/bin/env bash

except "$@" | xargs -0 ls
4
Helper Method

Extglobの代替として(非常に良い答えであり、誰もが.bashrcにshopt -s extglob globstarを含める必要があります)、 $ GLOBIGNOREグローバル変数 を使用できます。 「foo.txt」と「bar baz.txt」を除くすべてのファイルを取得するとします。

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

...ただし、これにより、シェルオプションdotglobがオンになります。つまり、*は、ドットで始まるファイル(通常は非表示)に一致します。したがって、実際には2つのコマンドが必要です。

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

これはグローバル変数であるため、ログアウトまたは次のいずれかの方法で$ GLOBSTARが設定解除されるまで、使用するすべてのグロブに影響します

GLOBIGNORE=

また、変数に渡されたリテラル文字列でのみ機能します。 $ GLOBIGNOREを設定し、これらのコマンドの違いを見ると、私が何を意味するかがわかります。

printf '%s\n' *
printf '%s\n' ./*
1
evilsoup