最近、予期せぬ方法で拡大したシェルパターンが原因で少し事故が発生しました。 /root
ディレクトリにある一連のドットファイルの所有者を変更したかったので、変更しました
chown -R root .*
当然、.*
は..
に拡張されましたが、これはちょっとした惨事でした。
bash
でこの動作はシェルオプションを調整することで変更できることを知っていますが、デフォルト設定でディレクトリ内のすべてのドットファイルに展開されるが.
には展開されないパターンはありますかと..
?
Bash、ksh、zshの方が優れたソリューションがありますが、この回答ではPOSIXシェルを想定しています。
パターン.[!.]*
は、ドットで始まり、ドット以外の文字が続くすべてのファイルに一致します。 ([^.]
は一部のシェルでサポートされていますが、すべてではないことに注意してください。ワイルドカードパターンの文字セット補数の移植可能な構文は[!.]
です。)したがって、.
と..
は除外されます。また、2つのドットで始まるファイルもあります。パターン..?*
は、2つのドットで始まり、..
だけではないファイルを処理します。
chown -R root .[!.]* ..?*
これは、すべてのファイルに一致するように設定された古典的なパターンです。
* .[!.]* ..?*
このアプローチの制限は、パターンの1つが何にも一致しない場合、それがコマンドに渡されることです。スクリプトでは、.
と..
を除くディレクトリ内のすべてのファイルを照合する場合、いくつかの解決策があり、それらはすべて面倒です。
* .*
を使用してすべてのエントリを列挙し、ループ内の.
と..
を除外します。パターンの一方または両方が何にも一致しない可能性があるため、ループは各ファイルの存在を確認する必要があります。他の基準でフィルタリングする機会があります。たとえば、ぶら下がっているシンボリックリンクをスキップする場合は、-h
テストを削除します。
for x in * .*; do
case $x in .|..) continue;; esac
[ -e "$x" ] || [ -h "$x" ] || continue
somecommand "$x"
done
コマンドが1回だけ実行される、より複雑なバリアント。位置パラメータが破壊されていることに注意してください(POSIXシェルには配列がありません)。これが問題になる場合は、これを別の関数に入れてください。
set --
for x in * .[!.]* ..?*; do
case $x in .|..) continue;; esac
[ -e "$x" ] || [ -h "$x" ] || continue
set -- "$@" "$x"
done
somecommand "$@"
* .[!.]* ..?*
トリプティクを使用します。この場合も、1つ以上のパターンが一致しない可能性があるため、既存のファイル(ぶら下がっているシンボリックリンクを含む)を確認する必要があります。
for x in * .[!.]* ..?*; do
[ -e "$x" ] || [ -h "$x" ] || continue
somecommand "$x"
done
* .[!.]* ..?*
tryptichを使用し、パターンごとに1回コマンドを実行しますが、何かに一致する場合に限ります。これにより、コマンドが1回だけ実行されます。位置パラメータが破壊されていることに注意してください(POSIXシェルには配列がありません)。これが問題になる場合は、これを別の関数に入れてください。
set -- *
[ -e "$1" ] || [ -h "$1" ] || shift
set -- .[!.]* "$@"
[ -e "$1" ] || [ -h "$1" ] || shift
set -- ..?* "$@"
[ -e "$1" ] || [ -h "$1" ] || shift
somecommand "$@"
find
を使用します。 GNUまたはBSD検索では、オプション-mindepth
および-maxdepth
を使用すると、再帰を簡単に回避できます。POSIX検索では、少し注意が必要ですが、実行できます。このフォームファイルごとに1回ではなく、1回だけコマンドを簡単に実行できるという利点があります(ただし、これは保証されません。結果のコマンドが長すぎると、コマンドは複数のバッチで実行されます)。
find . -name . -o -exec somecommand {} + -o -type d -Prune
これは、すべてのファイル名に少なくとも3文字(ドットを含む)が含まれている場合に機能します。
chown -R root .??*
より堅牢なソリューションとして、find
を使用できます。
find . -maxdepth 1 -name '.*' -exec chown -R root {} \;