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

标签 shell perl ksh

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

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

我尝试了几种不同的选项,因为 ksh/bash 在处理变量和比较方面往往有很多方法可以做相同或相似的事情。我也不太清楚这个非常古老的 Perl 代码到底是如何运行的。

我的 Perl 代码:

open(FILEIN,"base.dat") || die "Could not open FILEIN\n.";

open(FILEOUT1,">base1.dat") || die "Could not open FILEOUT1\n.";
open(FILEOUT2,">base2.dat") || die "Could not open FILEOUT2\n.";
open(FILEOUT3,">base3.dat") || die "Could not open FILEOUT3\n.";

$v_break =  "518000000";
$v_break2 = "525000000";

#Run until end of file
while (<FILEIN>)   {
  $v_pcn = substr($_, 0, 9);

  if ($v_break gt $v_pcn) {
     print FILEOUT1 $_;
  }
  elsif (($v_pcn ge $v_break) && ($v_pcn lt $v_break2)) {
     print FILEOUT2 $_;
  }
  else
  {
    print FILEOUT3 $_;
  }
}  #(<FILEIN>)

close(FILEIN);
close(FILEOUT1);
close(FILEOUT2);
close(FILEOUT3);

我的 Shell 脚本 (ksh):

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 >> 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 < base.dat

我希望 shell 脚本生成 3 个与 perl 代码生成的输出文件相匹配的输出文件,并且时间大约相同;

输入:

-rw-r--r--. 1 mfadjobt mfadset 2095795750 Feb 13 10:07 base.dat

输出:

-rw-r--r--. 1 mfadjobt mfadset  461650125 Feb 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 Feb 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

这将打开文件一次,维护文件的指针,并且应该有助于极大地加快速度。

通常,当 shell 运行缓慢时,这是由于您正在运行的命令造成的,但这里没有任何内容会生成子 shell,所以我会看看下一个最可能的罪魁祸首 - 文件处理。这就是我在这里看到的。

关于shell - 使用 If-Then-Else 将文件拆分为 3 个文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54678437/

相关文章:

linux - 我需要 solaris 的文件大小警报脚本

linux - 在 csh 中运行 unix ksh 命令

perl - 僵尸有何危害?

java - KSH 使用变量中的参数运行 Java

unix - 无法在 korn 脚本中的每行末尾插入日期和主机名

shell - 用 sed 替换单个空格而不接触多个空格

linux - 从查找中排除文件列表

c++ - 使用线程c++执行shell命令

regex - Perl 匹配正则表达式的哪些细微差别会引起头痛?

perl - 如何使用 unix 管道将 ls 命令的输出输出到 perl 脚本中