Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 使用If-Then-Else将文件拆分为3个文件_Shell_Perl_Ksh - Fatal编程技术网

Shell 使用If-Then-Else将文件拆分为3个文件

Shell 使用If-Then-Else将文件拆分为3个文件,shell,perl,ksh,Shell,Perl,Ksh,为什么用Perl编写的拆分大文件的代码要比用KornShell编写的代码运行得快得多。超过一百万条输入记录。每个记录的前9个字符用于确定将记录写入哪个文件,在Perl中运行大约需要4-5分钟。 我尝试将此代码转换为ksh,它似乎永远运行(小时) 我真的不知道我做错了什么导致了这个问题。在某些记录中,字符串中嵌入了空白和/或字母字符,因此比较必须是字符串类型的比较。关于让我的ksh脚本获得perl性能有什么想法吗?为什么没有 我尝试了几种不同的选择,因为ksh/bash在处理变量和比较时往往有很多

为什么用Perl编写的拆分大文件的代码要比用KornShell编写的代码运行得快得多。超过一百万条输入记录。每个记录的前9个字符用于确定将记录写入哪个文件,在Perl中运行大约需要4-5分钟。 我尝试将此代码转换为ksh,它似乎永远运行(小时)

我真的不知道我做错了什么导致了这个问题。在某些记录中,字符串中嵌入了空白和/或字母字符,因此比较必须是字符串类型的比较。关于让我的ksh脚本获得perl性能有什么想法吗?为什么没有

我尝试了几种不同的选择,因为ksh/bash在处理变量和比较时往往有很多相同或类似的方法。我也不能很好地理解这个非常古老的Perl代码是如何运行的

我的Perl代码:

open(FILEIN,“base.dat”)| | die“无法打开FILEIN\n.”;
打开(FILEOUT1,“>base1.dat”)| | die“无法打开FILEOUT1\n.”;
打开(FILEOUT2,“>base2.dat”)| | die“无法打开FILEOUT2\n.”;
打开(FILEOUT3,“>base3.dat”)| | die“无法打开FILEOUT3\n.”;
$v_break=“518000000”;
$v_break2=“525000000”;
#运行到文件结束
而(){
$v_pcn=substr($_,0,9);
如果($v_break gt$v_pcn){
打印文件输出1$;
}
elsif($v_pcn ge$v_break)&($v_pcn lt$v_break2)){
打印文件输出2$;
}
其他的
{
打印文件输出3$;
}
}  #()
关闭(归档);
关闭(FILEOUT1);
关闭(FILEOUT2);
关闭(FILEOUT3);
我的Shell脚本(ksh):

读取inrec时读取基本文件,直到EOF 开始工作循环 v_pcn=${inrec:0:9}#获取v_pcn中的前9个字符 #v_pcn=${v_pcn/''/0}将空格替换为“0” 如果[$v_pcn<'518000000'];然后#pcn<“518000000” echo$inrec>>base1.dat#将rec写入“base1.dat” elif[[$v_pcn>'525000000'.$v|u pcn=='525000000'];然后#pcn>=“525000000” echo$inrec>>base3.dat#将rec写入“base3.dat” else#else>=“518000000”和<“525000000” echo$inrec>>base2.dat#将rec写入“base2.dat” fi 完成 我希望shell脚本生成3个输出文件,与perl代码生成的文件相匹配,并且时间大致相同

输入:

-rw-r--r--。1 mfadjobt mfadset 2095795750二月13日10:07 base.dat
输出:

-rw-r--r--。1 mfadjobt mfadset 461650125二月13日10:07 base1.dat
-rw-r--r--。1 mfadjobt mfadset 519783625 Feb 13 10:07 base2.dat
-rw-r--r--。1 mfadjobt mfadset 1114362000二月13日10:07 base3.dat

每次拥有
>filename
时,您都会再次打开文件,将指针移到文件末尾,然后在语句末尾再次关闭文件。最好保持文件打开

while read inrec                           # Read base file until EOF
 do                                        # Start work loop
    v_pcn=${inrec:0:9}                     # Get 1st 9 Characters in v_pcn
#   v_pcn=${v_pcn/' '/0}                   # Replace blanks with '0'
    if [[ $v_pcn < '518000000' ]]; then    # pcn < "518000000"
         echo $inrec >&3
    elif [[ $v_pcn > '525000000' || $v_pcn == '525000000' ]]; then  # pcn >= "525000000"
         echo $inrec >&4
    else                                   # else >= "518000000" & < "525000000"
         echo $inrec >&5
    fi
 done < base.dat 3>> base1.dat 4>> base2.dat 5>> base3.dat
读取inrec时读取基本文件,直到EOF 开始工作循环 v_pcn=${inrec:0:9}#获取v_pcn中的前9个字符 #v_pcn=${v_pcn/''/0}将空格替换为“0” 如果[$v_pcn<'518000000'];然后#pcn<“518000000” echo$inrec>&3 elif[[$v_pcn>'525000000'.$v|u pcn=='525000000'];然后#pcn>=“525000000” echo$inrec>&4 else#else>=“518000000”和<“525000000” 回声$inrec>&5 fi 完成>base1.dat 4>>base2.dat 5>>base3.dat 这将打开文件一次,维护指向文件的指针,并将大大加快速度


通常情况下,当shell运行缓慢时,这是由于您正在运行的命令造成的,但是这里没有生成子shell,所以接下来我来看看下一个最可能的罪魁祸首-文件处理。这就是我在这里看到的。Perl代码被编译成“二进制”表示。然后,该二进制表示由高度优化的解释器执行

另一方面,Shell脚本

  • 每次执行时都要分析每一行
  • 文件重定向在每次执行时都会重复
  • 通常执行外部命令,除非该命令恰好是shell内置命令
我不确定Korn shell有哪些内置组件,但bash有很多

执行外部命令代价高昂,因为它至少涉及
fork()
execve()
系统调用

通常,shell脚本只有在非常短的情况下才会比Perl脚本快,即当Perl编译器的启动成本高于实际代码执行时间时


简短的回答是:当您将shell脚本转换为等效的Perl脚本时,不要感到惊讶,它将运行得更快。

为了避免与文件描述符混淆,您可以使用for循环

for inrec in `cat base.dat`                           # Read base file until EOF
 do                                        # Start work loop
    v_pcn=${inrec:0:9}                     # Get 1st 9 Characters in v_pcn
#   v_pcn=${v_pcn/' '/0}                   # Replace blanks with '0'
    if [[ $v_pcn < '518000000' ]]; then    # pcn < "518000000"
         echo $inrec >> base1.dat          # write rec to "base1.dat"
    elif [[ $v_pcn > '525000000' || $v_pcn == '525000000' ]]; then  # pcn >= "525000000"
         echo $inrec >> base3.dat          # write rec to "base3.dat"
    else                                   # else >= "518000000" & < "525000000"
         echo $inrec >> base2.dat          # write rec to "base2.dat"
    fi
 done
对于'cat base.dat'中的inrec,读取基本文件直到EOF
开始工作循环
v_pcn=${inrec:0:9}#获取v_pcn中的前9个字符
#v_pcn=${v_pcn/''/0}将空格替换为“0”
如果[$v_pcn<'518000000'];然后#pcn<“518000000”
echo$inrec>>base1.dat#将rec写入“base1.dat”
elif[[$v_pcn>'525000000'.$v|u pcn=='525000000'];然后#pcn>=“525000000”
echo$inrec>>base3.dat#将rec写入“base3.dat”
else#else>=“518000000”和<“525000000”
echo$inrec>>base2.dat#将rec写入“base2.dat”
fi
完成

仅使用
bash
进行测试,但下一个解决方案也应该使用一些
ksh
版本。 首先,重新考虑边界。东亚银行
tee < base.dat \
    >(grep -E "^([0-4]|50|51[0-7])"    > base1.dat) \
    >(grep -E "^5(1[89]|2[0-4])"       > base2.dat) |
      grep -E "^(52[5-9]|5[3-9]|6-9])" > base3.dat