残念ながら、シェル拡張に基づくすべてのソリューションは、最大コマンドラインの長さによって制限されます。どちらが変わるか(調べるにはtrue | xargs --show-limits
を実行してください);私のシステムでは、約2メガバイトです。はい、多くの人は、それが十分であると主張します - ビルゲイツは640キロバイトで1回でした。
(共有されていないファイルシステムで特定の並列シミュレーションを実行すると、収集フェーズで同じディレクトリに数十万のファイルがあることがあります。データを収集する最も堅牢な方法です。ごくわずかなPOSIXユーティリティが、 "Xは誰にとっても十分だ"と思うほど馬鹿だ。)
幸い、いくつかの解決法がある。一つは、代わりにfind
を使用することです。(あなたは出力をソートしたい場合は、
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\n'");
セパレータとして\0
を使用します。
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d");
はまた、あなたが望むように、ロケールに依存しない、出力をフォーマットすることができますファイル名に改行を含めることができるため)-t=
sort
には、\0
をセパレータとしても使用できます。あなたが名前をしたい場合は、配列内の
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\0' | sort -t= | tr -s '\0' '\n'");
代わりglob()
関数を使用する:tr
はあなたのために改行に変換します。私が今しておきハープたいと
最後に、1は内部でこれを実装するためにPOSIX nftw()
機能を使用することができます。
#define _GNU_SOURCE
#include <stdio.h>
#include <ftw.h>
#define NUM_FDS 17
int myfunc(const char *path,
const struct stat *fileinfo,
int typeflag,
struct FTW *ftwinfo)
{
const char *file = path + ftwinfo->base;
const int depth = ftwinfo->level;
/* We are only interested in first-level directories.
Note that depth==0 is the directory itself specified as a parameter.
*/
if (depth != 1 || (typeflag != FTW_D && typeflag != FTW_DNR))
return 0;
/* Don't list names starting with a . */
if (file[0] != '.')
printf("%s/\n", path);
/* Do not recurse. */
return FTW_SKIP_SUBTREE;
}
とnftw()
コールを上記明らか
のようなものである使用します
nftw()
を使用して
if (nftw(".", myfunc, NUM_FDS, FTW_ACTIONRETVAL)) {
/* An error occurred. */
}
のみ「問題」は、ファイルのかなりの数は、関数が(NUM_FDS
)を使用することができ記述子を選択することです。 POSIXによると、プロセスは常に少なくとも20個のファイル記述子を開くことができなければなりません。標準のもの(入力、出力、およびエラー)を引くと、それは17になります。しかし、上記は3以上のものを使用する可能性は低いです。
sysconf(_SC_OPEN_MAX)
を使用して、プロセスが同時に使用する記述子の数を減算すると、実際の制限値を見つけることができます。現行のLinuxシステムでは、通常、プロセスあたり1024個に制限されています。
数字が4または5程度以上であれば、パフォーマンスにのみ影響します。回避方法を使用する前に、nftw()
がディレクトリツリー構造にどれだけ深く入るかを判断するだけです。 、そのディレクトリ利回りbash: /bin/ls: Argument list too long
エラーで
ls -d */
を実行している、私のシステムで
mkdir lots-of-subdirs
cd lots-of-subdirs
for ((i=0; i<100000; i++)); do mkdir directory-$i-has-a-long-name-since-command-line-length-is-limited ; done
:あなたはサブディレクトリのたくさんのテストディレクトリを作成したい場合は
は、以下のバッシュのようなものを使用しますfind
コマンドとnftw()
ベースのプログラムはすべて正常に動作します。
同じ理由でrmdir directory-*/
を使用してディレクトリを削除することもできません。代わりに
find . -name 'directory-*' -type d -print0 | xargs -r0 rmdir
を使用してください。または、ディレクトリとサブディレクトリ全体を削除するだけです。
cd ..
rm -rf lots-of-subdirs
「システム」と呼んでください。 Unix上のGlobは、シェルによって拡張されています。 'system'はあなたにシェルを与えます。 – PSkocik
ありがとう@PSkocik、それでした!回答を投稿したいですか? 'system("/bin/ls -d */");'なぜ 'execv()'がこのトリックを行えなかったのかを説明してください;) – gsamaras
'system()'を使うなら 'fork () 'を返します。 – unwind