1

I would like to replace the string "edit TRIES 2" by "edit TRIES 3" after a line that contains the string "task Listen"

  task Listen
    edit TRIES 2

How can I do it with sed ? The string "edit TRIES 2" appears several times in the file, so I cannot make a simple sed replacement, because I would like to replace that particular line.

3

How about simply

sed '/task Listen/{n; s/edit TRIES 2/edit TRIES 3/}' file

Ex. given

$ cat file
    edit TRIES 2
    edit TRIES 2
  task Listen
    edit TRIES 2
    edit TRIES 2

then

$ sed '/task Listen/{n; s/edit TRIES 2/edit TRIES 3/}' file
    edit TRIES 2
    edit TRIES 2
  task Listen
    edit TRIES 3
    edit TRIES 2
  • Thanks a lot! This suggestion solves my problem. – Vanda Aug 23 at 14:24
  • @Vanda, If the answer helped, you might consider accepting the answer by clicking the checkmark on the left side. – pLumo Aug 23 at 14:55
1

Or with the scriptable editor ed: search for the line containing "task Listen", go one beyond it, and replace any "edit TRIES 2" with "edit TRIES 3":

printf '%s\n' '/task Listen/+1 s/edit TRIES 2/edit TRIES 3/' 'wq' | ed -s file

The printf sends two newline-separated commands to ed (who is told to suppress diagnostics with -s):

  1. /task Listen/+1 -- on the following the one that matches "task Listen",
  2. s/edit TRIES 2/edit TRIES 3/ -- replace any "edit TRIES 2" with "edit TRIES 3"

If the line following "task Listen" does not contain "edit TRIES 2", ed will exit unsuccessfully (and not change the file).

0

This is my attempt:

sed -E 'N;s/([[:blank:]]*task Listen\n[[:blank:]]*edit TRIES )[0-9]*)/\13/' file

Use extended regular expressions:

sed -E

Use the command N (new line)

'N;

Match and capture the two lines, either if the beginning are spaces or tabs, in any repetition:

([[:blank:]]*task Listen\n[[:blank:]]*edit TRIES )[0-9]*

Replace the string with the captured pattern and the desired string, in this case 3:

/\13/
  • The [0-9]* at the end is not that relevant, but I leave to match the exact pattern. – guillermo chamorro Aug 22 at 18:33
  • Sorry for my previous comment, I totally missed the N command. However, you should use [[:blank:]] instead of [ \t] as most sed implementations would match space, backslash and the character t otherwise. – Kusalananda Aug 22 at 18:34
  • @Kusalananda yes, I always do it. So far it works, but I'm listening to your feedback. – guillermo chamorro Aug 22 at 18:35
0

The following sed scripts are based on the idea that a line containing zero-or-more spaces and the string "task Listen" defines the beginning of a block of text that you want to edit, and that the block continues until the next "task" or the end of the file (whichever comes first).

It works in cases where the 'edit TRIES 2' line may not immediately follow the task Listen line, but could be anywhere within the task Listen block.

It will also cope with variations in the number of spaces within the edit TRIES 2 line.

sed -E -e '/^ *task Listen/,/^ *task/ {s/edit +TRIES +2 *$/edit TRIES 3/}'

Extended regular expressions are enabled (with -E) so we can use + (1-or-more) without needing to escape it with a backslash. Also used for alternation (task|xyz) without backslash uglification in the second example.

The *$ at the end of the search regex ensures that it will only match 2 and not some other number beginning with 2.

For example, if given this as input:

$ cat input.txt 
  task something
    edit TRIES 2
  task Listen
    foo
    bar
    edit TRIES 25
    edit TRIES 2
  task somethingelse
    edit TRIES 2

It will produce the following output:

$ sed -E -e '/^ *task Listen/,/^ *task/ {s/edit +TRIES +2 *$/edit TRIES 3/1}' input.txt 
  task something
    edit TRIES 2
  task Listen
    foo
    bar
    edit TRIES 25
    edit TRIES 3
  task somethingelse
    edit TRIES 2

Note that it a) didn't change the TRIES 2 to TRIES 3 in either the preceding or following task block and b) did change TRIES 2 wherever it appeared in the "task Listen" block. NOTE: if "edit TRIES 2" occurs more than once in that block, all occurrences will be changed.

If the "task Listen" block is, or might be, terminated by something other than a line beginning with zero-or-more spaces and the word "task", you can change the second address to suit. e.g. if the block could end with either a new task block or an "xyz" block:

sed -E -e '/^ *task Listen/,/^ *(task|xyz)/ {s/edit +TRIES +2 *$/edit TRIES 3/1}'

To make either of the above sed commands actually change the input file rather than just the output stream, use sed's -i option.

Finally, if the input text might contain spaces and/or tabsinstead of just spaces, character you can use the [[:blank:]] character class to match them. e.g.

 sed -E -e '/^[[:blank:]]*task Listen/,/^[[:blank:]]*task/ {
   s/edit[[:blank:]]+TRIES[[:blank:]]+2[[:blank:]]*$/edit TRIES 3/}'

or, if your version of sed supports perl-compatible regular expressions (e.g. GNU sed):

sed -E -e '/^\s*task Listen/,/^\s*task/ {s/edit\s+TRIES\s+2\s*$/edit TRIES 3/}'
-1

Tried with Below command and it worked fine

command

sed -n '/task Listen/,+1p' filename| sed "s/edit TRIES 2/edit TRIES 3/g"

output

task Listen
    edit TRIES 3
  • Unfortunately, this would remove all lines before "task Listen" as well as all lines from +1 onward. – Jeff Schaller Aug 23 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.