-exec のない find を使用してディレクトリ権限を再帰的に設定するにはどうすればよいですか?

-exec のない find を使用してディレクトリ権限を再帰的に設定するにはどうすればよいですか?

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 文字のようなものに置き換える必要があるでしょう。しかし、この の不具合のあるバージョンでも同様の操作が必要になります。findfind

答え1

の出力は、find改行で区切られたファイル名を出力します1。これは が要求する形式ではなくxargs、が要求するfind形式を生成する方法もありませんxargs。入力は空白で区切られた項目として解析され、\'"引用符として が使用されます。 の一部のバージョンはxargs改行で区切られた入力を受け付けますが、 にfind標準オプションがない場合は、 にも標準オプションがある可能性がありますxargs

find . -type d | xargs chmod g+sディレクトリ名に空白や が含まれていない限り、 は\'"機能します。シェルにとって意味のある$1: はありませんが、 の出力を解析して に渡すのにシェルは関与せず、 のみがfind関与することに注意してください。chmodxargs

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複数のスラッシュを自発的に出力しないため、トラバースするディレクトリへのパスを入力すると、出力でこれを認識できます。 以下は、 の出力をの入力形式に//変換するためにこの事実を使用する、最小限のテスト済みのコードです。findxargs

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 を使用します。

関連情報