Perl可以管理数百万个文件吗?
我喜欢编写自己的脚本,在bash中绘制一些数据。 无论如何,现在我有数千个文件要“重命名”、“编辑” 还有更多 当我试图管理这些文件时,shell会说Perl可以管理数百万个文件吗?,perl,Perl,我喜欢编写自己的脚本,在bash中绘制一些数据。 无论如何,现在我有数千个文件要“重命名”、“编辑” 还有更多 当我试图管理这些文件时,shell会说 $Arguments list too long 我想知道Perl是否可以管理这么多的文件?Unix上允许的参数加环境的长度有一个上限。对于许多现代版本的Unix,这个限制大约是256kib,而对于其他版本,这个限制可能更小 这不是shell本身的限制,也不是Perl或任何其他程序的限制,而是Unix内核施加的限制 如果一次处理一个文件,Per
$Arguments list too long
我想知道Perl是否可以管理这么多的文件?Unix上允许的参数加环境的长度有一个上限。对于许多现代版本的Unix,这个限制大约是256kib,而对于其他版本,这个限制可能更小 这不是shell本身的限制,也不是Perl或任何其他程序的限制,而是Unix内核施加的限制 如果一次处理一个文件,Perl总共可以处理数百万个文件。困难在于将文件列表传递给Perl。您可以将名称写入文件,并告诉Perl要读取哪个文件。您可以使用
xargs
。您必须担心什么标记文件名的结尾。安全答案是空字节;它是Unix中唯一不能出现在路径名中的字符。您会发现使用POSIX函数读取这些行是最简单的。使用换行符是常规的,但不是100%;文件名可能包含换行符,导致混淆
您还可以让Perl自己生成文件列表,方法是读取目录(逐段,但不会一次将数百万个名称拖到内存中),或者使用函数,例如
另见
此代码可以帮助您确定参数列表上的限制;这是对我对交叉引用问题的回答的改进。它告诉我MacOSX10.8.5上的256kib。在一个古老的Linux2.6内核上,我得到了128kib的限制
/* SO 18559403: How big an argument list is allowed */
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
extern char **environ; /* Sometimes in <unistd.h> */
enum { BYTES_PER_KIBIBYTE = 1024 };
enum { BYTES_PER_MEBIBYTE = BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE };
enum { E_GOT_E2BIG = 37 };
enum { E_NOT_E2BIG = 219 };
enum { R_TOO_LARGE = +1, R_TOO_SMALL = -1 };
static char *print_kib(int size, char *buffer, size_t buflen)
{
snprintf(buffer, buflen, "%d (%d KiB)", size, size / BYTES_PER_KIBIBYTE);
return buffer;
}
static int test_arg_size(int size)
{
char buffer[32];
int result = R_TOO_SMALL;
assert(size % 8 == 0);
fflush(0);
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "Failed to fork at size %s\n",
print_kib(size, buffer, sizeof(buffer)));
exit(1);
}
else if (pid == 0)
{
int self = getpid();
printf("Child: %d\n", self);
char *args[10] = { "ls" };
size_t bytes_per_arg = size / 8;
for (int j = 1; j < 9; j++)
{
args[j] = malloc(bytes_per_arg);
if (args[j] == 0)
{
fprintf(stderr, "Failed to allocate argument space at size %s\n",
print_kib(size, buffer, sizeof(buffer)));
exit(E_NOT_E2BIG);
}
memset(args[j], j + '0', bytes_per_arg - 1);
args[j][bytes_per_arg - 1] = '\0';
}
/* Close standard I/O channels so executed command doesn't spew forth */
int dev_null = open("/dev/null", O_RDWR);
if (dev_null < 0)
{
fprintf(stderr, "Failed to open /dev/null for reading and writing\n");
exit(E_NOT_E2BIG);
}
int dev_stderr = dup(2);
if (dev_stderr < 0)
{
fprintf(stderr, "Failed to dup() standard error\n");
exit(E_NOT_E2BIG);
}
close(0);
dup(dev_null);
close(1);
dup(dev_null);
close(2);
dup(dev_null);
close(dev_null);
/* Execute ls on big file names -- error is ENAMETOOLONG */
execvp(args[0], args);
/* Reinstate standard error so we can report failure */
dup2(dev_stderr, 2);
int errnum = errno;
if (errnum == E2BIG)
{
fprintf(stderr, "%d: got E2BIG (%d: %s) at size %s\n",
self, errnum, strerror(errnum),
print_kib(size, buffer, sizeof(buffer)));
exit(E_GOT_E2BIG);
}
fprintf(stderr, "%d: got errno %d (%s) at size %s\n",
self, errnum, strerror(errnum),
print_kib(size, buffer, sizeof(buffer)));
exit(E_NOT_E2BIG);
}
else
{
int self = getpid();
int corpse;
int status;
while ((corpse = waitpid(pid, &status, 0)) != -1)
{
if (!WIFEXITED(status))
printf("%d: child %d died with exit status 0x%.4X", self, corpse, status);
else
{
int statval = WEXITSTATUS(status);
printf("%d: child %d died with exit status %d: ", self, corpse, statval);
switch (statval)
{
case E_GOT_E2BIG:
printf("success: got E2BIG");
result = R_TOO_LARGE;
break;
case E_NOT_E2BIG:
printf("failed: indeterminate error in child");
break;
case 1:
printf("command exited with status 1 - it worked");
break;
default:
printf("unknown: unexpected exit status %d", statval);
break;
}
}
printf(" at size %s\n", print_kib(size, buffer, sizeof(buffer)));
fflush(stdout);
}
}
return result;
}
static int env_size(void)
{
int size = 0;
for (char **ep = environ; *ep != 0; ep++)
size += strlen(*ep) + 1;
return size;
}
int main(void)
{
int env = env_size();
int lo = 0;
int hi = BYTES_PER_MEBIBYTE;
/* Binary search -- the kilobyte slop means termination does not have to be accurate */
while (lo + 1 * BYTES_PER_KIBIBYTE < hi)
{
int mid = (lo + hi) / 2;
if (test_arg_size(mid) == R_TOO_LARGE)
hi = mid;
else
lo = mid;
}
char buffer1[32];
char buffer2[32];
printf("Environment size = %d\n", env);
printf("Best guess: maximum argument size in range %s to %s\n",
print_kib(lo + env, buffer1, sizeof(buffer1)),
print_kib(hi + env, buffer2, sizeof(buffer2)));
return 0;
}
/*SO 18559403:允许的参数列表有多大*/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
外部字符**环境;/*有时在*/
枚举{BYTES_PER_KIBIBYTE=1024};
枚举{BYTES_PER_MEBIBYTE=BYTES_PER_KIBIBYTE*BYTES_PER_KIBIBYTE};
枚举{E_GOT_E2BIG=37};
枚举{E_NOT_E2BIG=219};
枚举{R_TOO_LARGE=+1,R_TOO_SMALL=-1};
静态字符*print\u kib(整数大小、字符*buffer、大小\u t buflen)
{
snprintf(缓冲区,buflen,“%d(%d KiB)”,大小,大小/字节/KIBIBYTE);
返回缓冲区;
}
静态整数测试参数大小(整数大小)
{
字符缓冲区[32];
int result=R\u太小;
断言(大小%8==0);
fflush(0);
pid_t pid=fork();
if(pid<0)
{
fprintf(stderr,“未能在大小为%s时分叉\n”,
打印(大小、缓冲区、大小(缓冲区));
出口(1);
}
否则如果(pid==0)
{
int self=getpid();
printf(“子项:%d\n”,self);
char*args[10]={“ls”};
size\u t bytes\u per\u arg=size/8;
对于(int j=1;j<9;j++)
{
args[j]=malloc(字节/arg);
如果(args[j]==0)
{
fprintf(stderr,“未能分配大小为%s的参数空间\n”,
打印(大小、缓冲区、大小(缓冲区));
出口(E_非E_E2BIG);
}
memset(args[j],j+'0',字节/arg-1);
args[j][bytes_per_arg-1]='\0';
}
/*关闭标准I/O通道,这样执行的命令就不会喷出*/
int dev_null=open(“/dev/null”,O_RDWR);
if(dev_null<0)
{
fprintf(stderr,“无法打开/dev/null进行读写\n”);
出口(E_非E_E2BIG);
}
int dev_stderr=dup(2);
如果(偏差小于0)
{
fprintf(stderr,“未能复制()标准错误\n”);
出口(E_非E_E2BIG);
}
关闭(0);
dup(dev_null);
关闭(1);
dup(dev_null);
关闭(2);
dup(dev_null);
关闭(dev_null);
/*在大文件名上执行ls--错误为enametolong*/
execvp(args[0],args);
/*恢复标准错误,以便我们可以报告失败*/
dup2(开发标准,2);
int errnum=errno;
如果(errnum==E2BIG)
{
fprintf(stderr,“%d:获取了大小为%s的E2BIG(%d:%s)\n”,
self、errnum、strerror(errnum),
打印(大小、缓冲区、大小(缓冲区));
出口(E_GOT_E2BIG);
}
fprintf(stderr,“%d:获取错误号%d(%s),大小为%s\n”,
self、errnum、strerror(errnum),
打印(大小、缓冲区、大小(缓冲区));
出口(E_非E_E2BIG);
}
其他的
{
int self=getpid();
int尸体;
智力状态;
while((尸体=waitpid(pid,&status,0))!=-1)
{
如果(!妻子退出(状态))
printf(“%d:孩子%d死亡,退出状态为0x%.4X”,自我,尸体,状态);
其他的
{
int statval=WEXITSTATUS(状态);
printf(“%d:child%d已死亡,退出状态为%d:”,self,comble,statval);
开关(statval)
{
案例E_变得更大:
printf(“成功:大获成功”);
结果=R_过大;
打破
案例E_不_E2BIG:
printf(“失败:子项中存在不确定错误”);
打破
案例1:
printf(“命令已退出,状态为1-已工作”);
打破
违约:
printf(“未知:意外退出状态%d”,statval);
打破
}
}
printf(“大小为%s\n”,print_kib(大小、缓冲区、大小(缓冲区)));
fflush(stdout);
}
}
返回结果;
}
静态整数环境大小(空)
{
int size=0;
对于(char**ep=environ;*ep!=0;ep++)
尺寸+=标准长度(*ep)+1;
返回大小;
}
内部主(空)
{
int env=env_size();
int-lo=0;
int hi=每兆字节字节数;
/*二进制搜索——千字节的slop表示终止不存在
$ find (your find command) > /tmp/files
$ your_prg.pl /tmp/files
#!perl
my $filelist = shift @ARGV;
open(my $fh,'<',$filelist) or die $!;
while (my $filename = <$fh>){
chomp $filename;
### do whatever want to do with the file
}