
find
私の Qnap NAS はパラメータがないコマンドに悩まされている-exec
ので、パイプで接続する必要があります。シェルは GNU bash、バージョン 3.2.57(2)-release-(arm-unknown-linux-gnueabihf) です。
現在のディレクトリのすべてのサブディレクトリ (ファイルではない) に setgid ビットを設定しようとしています。
これは動作しません:
find . -type d | xargs chmod g+s $1
"$1"
、など"$(1)"
を使用して$("1")
も機能しません。これらはすべて、chmod
スペースを含むディレクトリ名が 2 つ以上のパラメータとして渡されることを示します (サポートされているパラメータに関する標準のヘルプ メッセージが表示されます)。
xargs
必要がない場合は使用しません。いずれにしても、長い名前では詰まってしまうと思います。
以下およびその派生形は動作しません:
find . -type d | chmod g+s
find . -type d | chmod g+s "$1"
awk
引用符を挿入するためにまたは を使用することを考えましたsed
が、これを行うにはもっと簡単な方法があると思います。 以前は何をしていたのでしょうか-exec
? (悲しいことに、私はおそらく 1995 年頃には知っていたのですが、ずっと前に忘れてしまいました。)
PS: これらのディレクトリ名の多くには、Unicode 文字や 記号などが含まれます。?
これらは、比較的寛容な macOS に由来しています。そうは言っても、Windows がそれらで詰まらないように、すべてのインスタンスを?
Unicode 文字のようなものに置き換える必要があるでしょう。しかし、この の不具合のあるバージョンで⁇
も同様の操作が必要になります。find
find
答え1
の出力は、find
改行で区切られたファイル名を出力します1。これは が要求する形式ではなくxargs
、が要求するfind
形式を生成する方法もありませんxargs
。入力は空白で区切られた項目として解析され、\'"
引用符として が使用されます。 の一部のバージョンはxargs
改行で区切られた入力を受け付けますが、 にfind
標準オプションがない場合は、 にも標準オプションがある可能性がありますxargs
。
find . -type d | xargs chmod g+s
ディレクトリ名に空白や が含まれていない限り、 は\'"
機能します。シェルにとって意味のある$1
: はありませんが、 の出力を解析して に渡すのにシェルは関与せず、 のみがfind
関与することに注意してください。chmod
xargs
find
があり-print0
、 がxargs
ある場合-0
、これらのオプションを使用して、任意のファイル名で機能する null 区切りのファイル名を渡すことができます。
find . -type d -print0 | xargs -0 chmod g+s
xargs
が標準オプション をサポートしている場合は-I
、これを使用して、各行を空白で区切られた引用符付き文字列としてではなく、項目として処理するように指示できます。これはスペースには対応しますが、\"'
や改行には対応しません。
find . -type d | xargs -I {} chmod g+s {}
シェルを使用して、 の代わりに行をループすることができますxargs
。これは、改行文字を含まないファイル名に対して機能します。
find . -type d | while IFS= read -r line; do chmod g+s "$line"; done
これらのソリューションは両方とも、改行文字を含まないファイル名にのみ機能します。 改行文字find
を含むファイル名での の出力は、解析が困難な 1 つのケースを除いてあいまいです。 は、find
複数のスラッシュを自発的に出力しないため、トラバースするディレクトリへのパスを入力すると、出力でこれを認識できます。 以下は、 の出力をの入力形式に//
変換するためにこの事実を使用する、最小限のテスト済みのコードです。find
xargs
chars=$(printf '\t "'\\\')
{ find .//. -type d; echo .// } | LC_ALL=C sed -n '
s/['"$chars"']/\\&/g
/^\.\/\// {
x
s/\n/\\&/g
p
b
}
H' | LC_ALL=C xargs chmod g+s
1 より正確には、改行で終了します (姓の後に改行があります)。
答え2
bash を使って自分で再帰を実行することもできます。次のようになります:
shopt -s nullglob dotglob
recurse_chmod () (
cd "$1"
for d in ./*/
do
if [ -L "$d" ]; then continue; fi
chmod g+s "$d"
recurse_chmod "$d"
done
)
recurse_chmod .
答え3
xargsに\0を区切り文字として使用するように指示することができますfind . -type d -print0 | xargs -0 chmod g+s
または
find . -type d | xargs -I{} -d '\n' chmod g+s "{}"
. 区切り文字として \n を使用します。