在awk中正确使用close避免文件句柄泄露

有时我们需要用shell脚本处理一些文件,通常我们会使用awk这个强大的可编程命令来处理文本文件,当我们在一次awk调用中处理很多文件时,如果没有正确的关闭打开的文件和管道,则会造成文件句柄泄露,awk命令会报错,我们通过以下测试说明这个问题,并看看如何正确的使用close命令解决这个问题。

我们先用ulimit命令查看一个进程最多可以打开多少个文件句柄:

ulimit -n

通常是1024。

生成一批测试文件,数量超过1024,这里我们生成了10000个文件用于测试:

mkdir test
cd test
for ((i=0; i < 10000; ++i)); do 
    filename=$(printf "file%04d" $i); 
    echo $filename; 
    for ((j=0; j < 10; ++j)); do  
        echo line$j >> ${filename}; 
    done; 
done

我们来看看下面这个awk命令的执行情况:

ls file* | awk 'BEGIN {
    count=0;
}
{
    file=$0;
    if (getline line <file)
    {
        count++;
    }
}
END {
    print count;
}'

这个命令用于统计非空文件的个数,当然这不是最好的方法,在这里只用于awk打开文件的测试,命令执行时会提示:

awk: cmd. line:6: (FILENAME=- FNR=1022) fatal: too many pipes or input files open

可见打开了太多的文件,可以在if语句后面加上close来关闭打开的文件以解决这个问题,如下:

ls file* | awk 'BEGIN {
    count=0;
}
{
    file=$0;
    if (getline line <file)
    {
        count++;
    }
    close(file);
}
END {
    print count;
}'

除了打开文件占用文件句柄之外的另一种占用文件句柄的情况就是调用shell命令并用管道处理,这种情况也要用close关闭打开管道,close的参数必须与打开管道的命令字符串完全一致,例如:

ls file* | awk 'BEGIN {
    count=0;
}
{
    file=$0;
    while ("cat "file | getline line)
    {
        count++;
    }
    close("cat "file);
}
END {
    print count;
}'

这个问题有一个例外,就是我们用getline读入一个文件时,遇到文件结束(getline失败时)awk会自动关闭这个文件,不需要主动close,例如以下统计所有文件行数的命令是可以正确执行的,这个便利并不适用于管道,如上例所示,管道还是需要主动关闭的:

ls file* | awk 'BEGIN {
    count=0;
}
{
    file=$0;
    while (getline line <file)
    {
        count++;
    }
}
END {
    print count;
}'

以上测试在CentOS 7.3下进行,不同的awk版本可能结果不同

awk使用这种方式方便用户对文件和管道的流式操作,没有提供独立的打开文件和管道的命令,而是默默的记录了打开的文件和管道,在一次使用后并不自动关闭,后续使用时继续在已打开的句柄上操作,直到用户显示的关闭文件和管道为止,关闭后再次用到相同的文件和管道时会自动重新打开,而重新打开的文件就又从文件起始位置开始处理了,例如:

ls file0000 | awk '{
    file=$0;
    getline line < file;
    print line;
    getline line < file;
    print line;
    close(file);
    getline line < file;
    print line;
}'
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞花丝雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值