FreeBSD QandA 2111

FreeBSD QandA

Q. grep hoge * とすると、
     /usr/bin/grep: Argument list too long.
   となってしまいます。どうして?

A. 引数が長すぎるからです。

   ? や * などのワイルドカードの展開は sh や csh などのシェルが行います。その後、
   子プロセス (この場合は grep) を生成するのですが、このとき引数に指定できる長さ
   (バイト数) の上限は /usr/include/sys/syslimits.h で
     #define ARG_MAX 65536
   と設定されています。
     % sysctl kern.argmax
     kern.argmax: 65536
   としても参照できますが、動的な変更は不可能です。

   例えば、カレントディレクトリに 000000、000001、000002、000003…という
   ファイルがあった場合、
      grep hoge *
   とすると、シェルによって
      grep hoge 000000 000001 000002 000003 ....
   と展開されますが、そのときメモリ中には
      grep(\0)hoge(\0)000000(\0)000001(\0)000002(\0)000003 ....
   というデータが作成されます。このデータは execve(2) の第2引数に渡されますが、
   この長さが ARG_MAX を越えていた場合、カーネルがエラーを返し、シェルが
   Argument list too long というエラーを表示しているわけです。ちなみにこの
   データは、(execve が成功した場合は) 子プロセスの
     main(int argc, char **argv)
   の argv が指す領域となります。


   というわけで、こういう場合は、
     % echo * | xargs grep hoge
     % find . -type f | xargs grep hoge
     % find . -type f -print0 | xargs -0 grep hoge (ファイル名に空白などを含む場合)
   などとして、引数以外 (この場合は標準入出力) の方法でデータを受け渡します。

   また、とにかく引数に渡される文字列の長さを短くすればよいのですから、
     % grep hoge /usr/ports/*/*/pkg-plist
   が長すぎるなら
     % cd /usr/ports
     % grep */*/pkg-plist
   とすれば、`/usr/ports' の11バイト×ファイル数の分だけ短くなります。

   grep hoge * がダメで echo * が OK である理由は、sh や csh では echo が
   組み込みコマンドとなっていて、子プロセスを生成せず内部で処理するからです。
     echo が内部コマンドである証拠
       % sh
       $ type echo
       echo is a shell builtin
       $ csh
       % which echo
       echo is a shell built-in
   フルパスを指定して /bin/echo * とすれば、grep と同様に ARG_MAX の
   制限を受けます。


   参考:
     [FreeBSD-users-jp 53154] 以下のスレッド

間違い・追加情報を見付けた場合は、 修正案の投稿のしかた を読んだ上で、
QandA@jp.FreeBSD.org まで お知らせください。