Sed:意外的语法错误“(”

时间:2013-10-06 20:11:38

标签: perl sed runtime-error

我的file.txt看起来像这样:

C00010018;1;17/10/2013;17:00;18;920;113;NONE
C00010019;1;18/10/2013;17:00;18;920;0;NONE
C00010020;1;19/10/2013;19:00;18;920;0;NONE

我正在尝试做两件事:

  1. 选择$id_play作为第二个字段的行。
  2. 在这些行上将;替换为-
  3. 我的尝试:

    #!/usr/bin/perl
    
    $id_play=3;
    $input="./file.txt";
    $result = `sed s@^\([^;]*\);$id_play;\([^;]*\);\([^;]*\);\([^;]*\);\([^;]*\);\([^;]*\)\$@\1-$id_play-\2-\3-\4-\5-\6@g $input`;
    

    我收到了这个错误:

    sh: 1: Syntax error: "(" unexpected
    

    为什么?

3 个答案:

答案 0 :(得分:5)

你必须转义@个字符,在某些情况下添加2个反斜杠(感谢ysth!),在sed之间添加单引号并使其filter the lines。所以用这个代替:

$result = `sed 's\@^\\([^;]*\\);$id_play;\\([^;]*\\);\\([^;]*\\);\\([^;]*\\);\\([^;]*\\);\\([^;]*\\);\\([^;]*\\)\$\@\\1-$id_play-\\2-\\3-\\4-\\5-\\6-\\7\@g;tx;d;:x' $input`;

PS。无需调用sed并使用split即可以更加干净的方式实现您要做的工作。例如:

#!/usr/bin/perl
use warnings;
use strict;

my $id_play=3;
my $input="file.txt";
open (my $IN,'<',$input);
while (<$IN>) {
    my @row=split/;/;
    print join('-',@row) if $row[1]==$id_play;
}
close $IN;

答案 1 :(得分:0)

不需要从perl调用sed,因为perl正则表达式引擎已经内置并且更容易使用。上面的答案非常好。有了这样一个简单的数据集,另一种简单的方法可以更具惯用性(尽管可能有点混淆了......然后再说sed命令本身有点复杂!)将是:

#!/usr/bin/perl
use warnings;
use strict;

my $id_play = 3;
my @result = map { s/;/-/g; $_ } grep { /^\w+;$id_play;/ } <DATA>;
print @result;

__DATA__
C00010018;1;17/10/2013;17:00;18;920;113;NONE
C00010019;1;18/10/2013;17:00;18;920;0;NONE
C00010020;1;19/10/2013;19:00;18;920;0;NONE
C00010020;3;19/10/2013;19:00;18;920;0;NONE
C00010019;3;18/10/2013;17:00;18;920;0;NONE
C00010020;4;19/10/2013;19:00;3;920;0;NONE

假设文件不是太大,你可以使用带有正则表达式的grep来抓取你要查找的行,然后用替换运算符映射以将这些分号转换为连字符并将结果存储在列表中然后你可以打印出来。我使用代码下方的 DATA 块进行了测试,但不是从该块中读取,您可能会正常读入文件。

编辑:也忘了提到在sed中,'('和')'被视为文字常规字符,而不是正则表达式分组。如果你已经为sed设置了这样的东西,请使用sed的-r选项让它在正则表达式中使用这些字符。

答案 2 :(得分:0)

$ cat file
C00010018;1;17/10/2013;17:00;18;920;113;NONE
C00010019;2;18/10/2013;17:00;18;920;0;NONE
C00010020;3;19/10/2013;19:00;18;920;0;NONE
$ 
$ id_play=2                                                  
$ 
$ awk -v id="$id_play" -F';' -v OFS='-' '$2==id{$1=$1}1' file
C00010018;1;17/10/2013;17:00;18;920;113;NONE
C00010019-2-18/10/2013-17:00-18-920-0-NONE
C00010020;3;19/10/2013;19:00;18;920;0;NONE