It is currently Tue, 17 May 2022 01:35:44 GMT



 
Author Message
 SED question (1st line that matches expression)
All,

Is there any way I can have SED replace a string in only the 1st line
that matches an expression ?

Something like "/Record Number xxx/ s/foo/bar/" works but makes SED
read the whole file.  How can I prevent SED to search the remainder of
the document after the 1st match ??

Any ideas welcome!

Thank you



 Tue, 27 Apr 2004 18:47:57 GMT   
 SED question (1st line that matches expression)
On 9 Nov 2001, Stefan wrote:

I'm sure it can be done with sed (most things can), but it's easier to
write and understand with a less cryptic tool:

searchstring=foo
replacement=bar

awk  "/$searchstring/ && ! xx++ { sub(/$searchstring/,\"$replacement\") }
       {print}" "$@"

Or, to be even less cryptic:

awk  "/$searchstring/ && xx == 0  {
              xx = 1
              sub(/$searchstring/,\"$replacement\")
             }
           }

       {print}" "$@"

--
    Chris F.A. Johnson                        http://cfaj.freeshell.org
    ===================================================================
    My code (if any) in this post is copyright 2001, Chris F.A. Johnson
    and may be copied under the terms of the GNU General Public License



 Tue, 27 Apr 2004 21:06:55 GMT   
 SED question (1st line that matches expression)

head -1 |sed ....

---
mark



 Tue, 27 Apr 2004 22:53:26 GMT   
 SED question (1st line that matches expression)
On 9 Nov 2001 02:47:57 -0800, Stefan <sjo...@rocketmail.com> wrote:

sed -e '1,/Record Number xxx/{//s/foo/bar/;}'

But I'm not sure it will work with every shell (especially if "Record
Number xxx" is on the first line. Another solution:

sed -e '
  /Record Number xxx/{
    s/foo/bar/
    b1
  }
  p;d
  :1
  n;b1'

This is more likely to work with most seds.

--
Stphane



 Wed, 28 Apr 2004 02:20:24 GMT   
 SED question (1st line that matches expression)

Replace oldpat/newpat as required

$ cat sedfile
s:oldpat:newpat:g
tdone
b
:done
N
P
s/.*\n//
bdone

$ sed -f sedfile yourfile

                      ---- OR ----

perl -lpe "!$a and $a = s/oldpat/newpat/" tst.dat

---- HTH
Atul



 Wed, 28 Apr 2004 06:28:43 GMT   
 SED question (1st line that matches expression)
On 09 Nov 2001 18:20:24 GMT, I wrote:
[...]
                                     ^^^^^^^^^^^
                                     every sed

Or
sed -e '/Record Number xxx/!{
          p;d
        }
        s/foo/bar/
        :1
        n;b1'

--
Stphane



 Wed, 28 Apr 2004 21:43:29 GMT   
 SED question (1st line that matches expression)
Thanks for all replies.  What I forgot to mention is that
- I have only SED (win32...).  Awk would probably be a better tool for
this, but is not an option
- the result should be the WHOLE FILE with all records changed, not
only the changed part (so the head -1 or any filtering on the output
is not applicable)
- I use an input file for sed, since I am to replace several records
at the same time
like
/Record 456/ s/foo/bar/
/Record 236/ s/xyz/abc/
...
so question is if a 'q' command will only quit the current script
line, not the whole script.  I'll try suggestions for now... thanks!

Cheers



 Fri, 30 Apr 2004 17:47:21 GMT   
 SED question (1st line that matches expression)

Awk is available for win32 and might be worth getting, but you can
make do with sed alone, too: see below.

It will terminate the whole script and won't help you any.

In principle what you want could be done by using an explicit 'N' loop
like Atun suggested, but it gets totally unmanageable with more than
just a few record types.

I'd suggest using hold space for flagging which record types
have already been encountered, like this:

#! /bin/sed -f
/Record Number 1/{
x
/:1:/!s/$/:1:/
x
t1
b
:1
s/foo/bar/
/Record Number 2/{
x
/:2:/!s/$/:2:/
x
t2
b
:2
s/xyz/abc/

That's simple enough to generalize to any number of records
and any actions you want to do with their first occurrence,
although you may hit your sed's script length or other limits
at some point (classic sed can only handle up to 100 commands
in one script).

Note: if you want to do some further processing in the script
you must modify it a little (add a label after those and change
the 'b' commands accordingly).

--
Tapani Tarvainen



 Sat, 01 May 2004 17:07:22 GMT   
 SED question (1st line that matches expression)
On 12 Nov 2001 01:47:21 -0800, Stefan <sjo...@rocketmail.com> wrote:
[...]
[...]

Try this:

sed -e '1{x;G;}' yourfile | sed -e '
1,/Record 456/{//s/foo/bar/;}
1,/Record 236/{//s/xyz/abc/;}
1d'

--
Stphane



 Sun, 02 May 2004 06:07:19 GMT   
 SED question (1st line that matches expression)
Thanks, seems to work!  
You know the strange thing is, it goes even SLOWER than the quick 'n
dirty inefficient way I tried in the first place. (?!)
My idea is, perhaps if you start each address range with '1,' you
actually force sed to restart at the beginning of the file with each
script line?
I think in my syntax, sed goes through the whole file even for low
record numbers to change, however he scans the file only ONCE.
It looks like checking for only the 1st occurence of a line match
would only be better IF you have a very limited number of records to
change AND all changes are only on low record numbers.  Just thinking
out loud here.
Out of curiousity I'm still trying to figure out your suggestion
though.
What's the // before the s/ command ?  And why the {x;G;} in the first
seperated command?
Cheers,
Stefan


 Sun, 02 May 2004 23:43:28 GMT   
 SED question (1st line that matches expression)
Thanks for the effort, I haven't even tried this one out but oh my
looks pretty complex to me.  (read; I don't understand one bit of that
one;-)  Actually never thought my sed question was of such advanced
level.  I'm also trying this one out although it seems more difficult
for my applications, since the sed script I want to use is to be
output from another process.
Thanks again, impressive, I'm not even gonna bother asking you the
howabouts in your syntax.
Cheers
Stefan


 Sun, 02 May 2004 23:48:24 GMT   
 SED question (1st line that matches expression)

Perl is more suitable for this IMHO and it is available for Win32 from ActiveState.

C:\myperl\bash>type tst.pl

@pat = map { qr/$_/ } ( "Record 456", "Record 236", "Record 336" );

@reclist{ @pat } = ( [ 0, sub {  s/1/X/  } ],
                     [ 0, sub {  s/2/Y/g } ],
                     [ 0, sub {  s/3/Z/  } ] );
while(<>)
{
        for $regex ( keys %reclist ) # keys %reclist )
        {
                m/$regex/ and
                not $reclist{$regex}->[0]
                and $reclist{$regex}->[0] = $reclist{$regex}->[1]->();
        }
        print

C:\myperl\bash>type tst.dat
Record 456 1 1 1
Record 456 1
1
2
Record 236 2
4
Record 236 2
Record 236 2

C:\myperl\bash>perl tst.pl tst.dat
Record 456 X 1 1
Record 456 1
1
2
Record Y36 Y
4
Record 236 2
Record 236 2

Also, you can easily change the "@pat" list to use more powerful regexes.
Global substitute for "Record 236" ( As I have done ), case sensitivity etc.

----- HTH
Atul



 Mon, 03 May 2004 02:16:15 GMT   
 SED question (1st line that matches expression)

Perl is more suitable for this IMHO and it is available for Win32 from ActiveState.

C:\myperl\bash>type tst.pl

@pat = map { qr/$_/ } ( "Record 456", "Record 236", "Record 336" );

@reclist{ @pat } = ( [ 0, sub {  s/1/X/  } ],
                     [ 0, sub {  s/2/Y/g } ],
                     [ 0, sub {  s/3/Z/  } ] );
while(<>)
{
        for $regex ( keys %reclist ) # keys %reclist )
        {
                m/$regex/ and
                not $reclist{$regex}->[0]
                and $reclist{$regex}->[0] = $reclist{$regex}->[1]->();
        }
        print

C:\myperl\bash>type tst.dat
Record 456 1 1 1
Record 456 1
1
2
Record 236 2
4
Record 236 2
Record 236 2

C:\myperl\bash>perl tst.pl tst.dat
Record 456 X 1 1
Record 456 1
1
2
Record Y36 Y
4
Record 236 2
Record 236 2

Also, you can easily change the "@pat" list to use more powerful regexes.
Global substitute for "Record 236" ( As I have done ), case sensitivity etc.

----- HTH
Atul



 Mon, 03 May 2004 02:16:15 GMT   
 SED question (1st line that matches expression)
On 14 Nov 2001 07:43:28 -0800, Stefan <sjo...@rocketmail.com> wrote:
[...]

// is to reuse the last regexp
1,/Record 456/{//s/foo/bar/;}
means

if current line is between line 1 and the first one matching '/Record
456/', then if current line matches "/Record 456/" then substitute bar
for foo.

The problem is that if "Record 456" is on the first line, you'll have a
problem. That's why there's the "sed -e '1{x;G;}'" to include an initial
blank line, which is removed later by "1d"

Note that sed always only performs one pass. It's a *stream* editor.

--
Stphane



 Mon, 03 May 2004 03:29:40 GMT   
 SED question (1st line that matches expression)

It shouldn't do that, unless your sed is seriously broken.
It will, however, go through the file twice (once for each sed
invocation), and moreover it will test each pattern for every
line _and_ do it twice until it has been found.

The part within {} gets executed for every line until
/Record 456/ matches; the // keeps the 's' from
happening, but it also means the pattern match is
done again, effectively doubling the execution time
compared to simple "replace every time" script.

--
Tapani Tarvainen



 Mon, 03 May 2004 17:30:30 GMT   
 
   [ 16 post ]  Go to page: [1] [2]

Similar Threads

1. sed regular expressions matching

2. Sed multiple repexp expression match

3. Sed replacing half of the matched expressions

4. use SED to delete 1st line in a file

5. Sed: 1st line w/regex only

6. How to extract very 1st line of a file with sed or any:

7. sed expression for truncating line length

8. sed : an expression for the last but one line

9. Print Nth matching line with sed


 
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software