Bash在命令行上工作但不在perl脚本中

时间:2015-09-02 22:16:50

标签: bash perl sed

我有一套.csv文件,我试图清理。每个都有这样的数据:

x0,"","",""
x1,123,456,789
x2,123,456,789
x3,123,456,789
-,"","",""
x4,123,456,789
[space],____,____,____
x5,123,456,789
x6,===,====,======
x7,---,--------=--,-------

我想删除所有不是xn,###,###,###的行,所以在这个例子中,它将是第1,5,7,9和10行。在cygwin命令中我按1键输入以下命令:

    sed -i '/"",""/d' *.csv
    sed -i '/___/d' *.csv
    sed -i '/---/d' *.csv
    sed -i '/===/d' *.csv

这些都有效。但是,当我尝试将它们一起放入perl脚本时(我的其余代码都在perl中,它们会失败:

    system("sed -i '/"",""/d' *.csv");
    system("sed -i '/___/d' *.csv");
    system("sed -i '/---/d' *.csv");
    system("sed -i '/===/d' *.csv");

我得到了结果:

  

找到运算符在test1.pl第1行,#34;&#34; sed -i&#39; /&#34;&#34;,&#34;&#34; < / p>      

(在&#34之前缺少操作员;&#34;?)

     

找到运营商在test1.pl第1行,#34;&#34;&#34;&#34; / d&#39;附近的字符串*的.csv&#34;&#34;

     

(在&#34; / d&#39; * .csv&#34;?之前缺少操作员)

     

test1.pl第1行的语法错误,接近&#34;&#34; sed -i&#39; /&#34;&#34;,&#34;&#34;

我注意到除了第一个命令之外的所有工作 - sed中的""有什么特别之处吗?任何帮助,将不胜感激!我们也欢迎更简单的解决方案!

3 个答案:

答案 0 :(得分:2)

问题是sed参数中的双引号结束了Perl字符串。你需要逃避它们

system("sed -i '/`"`",`"`"/d' *.csv");

或者您可以使用q(...)

system(q(sed -i '/"",""/d' *.csv));

顺便说一句,您可以向sed提供多个命令,因此您不必多次运行它。

system(q(sed -i -e '/"",""/d' -e '/___/d' -e '/---/d' -e '/===/d' *.csv"));

或者您可以使用带有替换的正则表达式来同时匹配所有模式。

system(q(sed -i -e '/"",""\\|___\\|---/\\|===/d' *.csv"));

答案 1 :(得分:2)

如果你的脚本的其余部分是在Perl中,我强烈建议用本机实现替换你对sed的调用。

例如,您使用sed进行的替换可以替换为以下内容:

use strict;
use warnings;

for my $file (glob '*.csv') {
    open my $in, '<', $file;        
    my @lines;
    while (<$in>) {
        next if /"",""/;
        next if /___/;
        next if /---/;
        next if /===/;
        push @lines, $_;
    }
    close $in;

    # this will overwrite your files!
    # change $file to something else to test
    open my $out, '>', $file;
    print $out $_ for @lines;
}

循环遍历以.csv结尾的每个文件,读取每一行。它会跳过任何与其中一个模式匹配的行(如果需要,可以使用每个模式之间使用|的单个正则表达式执行此操作,但我将其保留为与调用sed相同的行)。它将任何剩余的行推送到数组。然后它重新打开输入文件进行写入并打印数组。

当然,它在行数方面略长,但它可以节省您在Perl功能强大时必须使用system来调用外部命令。这也意味着每个文件只打开一次,而不是像原始代码那样每次替换一次。

答案 2 :(得分:2)

使用转义字符\使解释器理解sed命令中的(“,*,。)与Perl(”,* ,.)不相同,而应将它们视为字符串模式用于sed命令。

    system("sed -i '/\"\",\"\"/d' \*\.csv");
    system("sed -i '/___/d' \*\.csv");
    system("sed -i '/---/d' \*\.csv");
    system("sed -i '/===/d' \*\.csv");