GNU bug report logs - #28056
Substitution doing global when it should not.

Previous Next

Package: sed;

Reported by: Techwolf Lupindo <techwolf.lupindo <at> gmail.com>

Date: Fri, 11 Aug 2017 20:15:01 UTC

Severity: normal

Tags: notabug

Done: Eric Blake <eblake <at> redhat.com>

Bug is archived. No further changes may be made.

Full log


View this message in rfc822 format

From: Assaf Gordon <assafgordon <at> gmail.com>
To: Techwolf Lupindo <techwolf.lupindo <at> gmail.com>, Eric Blake <eblake <at> redhat.com>
Cc: 28056-done <at> debbugs.gnu.org
Subject: bug#28056: Substitution doing global when it should not.
Date: Sat, 12 Aug 2017 19:51:57 -0600
Hello,

On 12/08/17 12:02 PM, Techwolf Lupindo wrote:
> A followup. I tried the command you hinted at. The result was the first
> match and substitution was done, but the rest of the file was deleted. This
> is using sed -i -e.

If you want to operate on just the first matching line, you can use
the following sed method:

  printf "%s\n" a b c d a b c d | sed '/b/ { s/b/X/ ; :Y ; n ; bY }'

The sed program does the following:

 /b/  - match *any* line that contains 'b'

 { ... } - sed commands grouped together, will be executed
          when the current line matches 'b'

 s/b/X/ - replace the first occurrence of 'b' with 'X' .

 :Y     - a label called 'Y' (arbitrary name)

 n      - read the next line and print it

 bY     - jump (=branch) to label Y


Effectively, the first time a line contains 'b'
matches the regex, sed will perform one replacement,
and then enter an endless loop of reading/printing the lines,
without executing any other sed commands (and thus,
not matching other 'b' lines and not performing replacements).

Expanding Eric's suggestion, your sed command might look like:

    sed -e '/COMMAND ${MERCURIAL}/ { s::COMMAND ${MERCURIAL} -- cwd
${CMAKE_SOURCE_DIR}: ; :Y ; n; bY }'


Also,
When experimenting with sed commands, I'd recommend not using "-i"
(in-place replacements) - this could lead to data loss if your sed
command isn't working as expected, and you don't have a backup.


Lastly,
For quick-and-dirty manual sed replacements of single lines, you can
find the exact line number and replace just it.
Example:

  $ wget https://hg....file/9d58c58cca90/indra/cmake/BuildVersion.cmake

  $ grep -n 'COMMAND ${MERCURIAL}' BuildVersion.cmake
  28:         #COMMAND ${MERCURIAL} log -r tip:0 --template '\\n'
  31:         COMMAND ${MERCURIAL} identify -n

And then assuming you want to change only line 28, use a specific
and even shorter sed command:

  sed '28s/}/} --cwd ${CMAKE_SOURCE_DIR} /' BuildVersion.cmake

The '28s/.../.../' tells sed to perform the 's' command only on line 28.

Hope this helps,

regards,
 - assaf








This bug report was last modified 7 years and 342 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.