0

I've got file.txt which looks like this:

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

And I'm trying to do two things:

  1. Select the lines that have $id_play as 2nd field.
  2. Replace ; with - on those lines.

My attempt:

#!/usr/bin/perl

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

And I'm getting this error:

sh: 1: Syntax error: "(" unexpected

Why?

Maria Ines Parnisari
  • 16,584
  • 9
  • 85
  • 130

3 Answers3

5

You have to escape the @ characters, add 2 backslashes in some cases (thanks ysth!), add single quotes between sed and make it also filter the lines. So replace with this:

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

PS. What you are trying to do can be achieved in a much more clean way without calling sed and using a split. For example:

#!/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;
Community
  • 1
  • 1
psxls
  • 6,807
  • 6
  • 30
  • 50
  • that doesn't work for me; I think some \ need to be doubled still – ysth Oct 06 '13 at 20:34
  • If I were to use the `$` anchor in the sed expression, do I have to escape it as well? – Maria Ines Parnisari Oct 06 '13 at 20:44
  • ysth I think you are right. no error is thrown, but the regex doesn't do what is supposed to. I'll check and update – psxls Oct 06 '13 at 20:47
  • thank you that's kind :) but actually it isn't again totally correct! it replaces the `;` to `-` but doesn't filter the lines! – psxls Oct 06 '13 at 20:55
  • I was assuming it wasn't supposed to filter them, but you may very well be right – ysth Oct 06 '13 at 20:57
  • @ysth, what other characters do I need to escape? And why, exactly?? – Maria Ines Parnisari Oct 06 '13 at 21:17
  • 1
    a command in backslashes uses perl's double-quotish interpolation, which allows interpolating variables (preceded by `$` or `@`) and backslash sequences (e.g. \n for a newline); so you need to escape $, @, and \. – ysth Oct 06 '13 at 21:24
  • @ysth, what about this? `$res = \`echo "$res" | grep '-66-[^-\]*-[^-]*-[^-]*\$'\`;` I'm getting an error: `grep: invalid option -- '-'` – Maria Ines Parnisari Oct 06 '13 at 21:32
  • 1
    grep interprets anything starting with - to be an option; make it `grep -e '-66...` – ysth Oct 06 '13 at 21:44
  • @ysth, ok, last question: `\`echo "$line" | sed 's/-[^-]*\$//g'\`` it's supposed to remove the last field of a line with - separated fields, but it doesn't work if the last field is made of words separated by blanks. Why? – Maria Ines Parnisari Oct 06 '13 at 21:56
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38698/discussion-between-l19-and-ysth) – Maria Ines Parnisari Oct 06 '13 at 22:36
0

No need to ever call sed from perl as the perl regex engine already built in and much easier to use. The above answer is perfectly fine. With such a simple dataset, another simple way to do it a little more idiomatically (although maybe a little more obfuscated...then again that sed command was a little complex in itself!) would be:

#!/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

Assuming the file isn't too terribly large, you can just use grep with a regex to grab the lines you are looking for, and then map with a substitution operator to covert those semicolons to hyphens and store the results in a list that you can then print out. I tested it with the DATA block below the code, but instead of reading in from that block, you would probably read in from your file as normal.

edit: Also forgot to mention that in sed, '(' and ')' are treated as literal regular characters and not regex groupings. If you're dead set on sed for such things, use the -r option of sed to have it use those characters in the regex sense.

drmrgd
  • 733
  • 5
  • 17
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
Ed Morton
  • 188,023
  • 17
  • 78
  • 185