Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert a line after pattern match, if only the string does not exists

Tags:

grep

sed

awk

Input file

Ranges:
- PeakK2:8.8.9
- rover-heal:3.3.1
Arg: V1
change: 1

Firstly, check if the string cpu-management exists in the file, if not add it after the rover-heal line like below.

Ranges:
- PeakK2:8.8.9
- rover-heal:3.3.1
- cpu-management:1.9.0
Arg: V1
change: 1

I came up with a one liner

grep -e "cpu-management:" test.yaml || sed -i -e "/rover-heal/- cpu-management:${version}/"  test.yaml

where version is the environmental variable.

Error:

sed: -e expression #1, char 16: unknown command: `-'
like image 539
voltas Avatar asked Apr 09 '21 12:04

voltas


3 Answers

This could be done with awk, please try following. You can use it as a single code.

awk -v val="${version}" '
FNR==NR{
  if($0~/cpu-management/){
    found=1
  }
  next
}
/rover/ && found==""{
  print $0 ORS "- cpu-management:" val
  next
}
1
' Input_file  Input_file

OR as per Ed sir's suggestion you could do following too use either above OR use following.

awk -v val="${version}" '
FNR==NR{
  if($0~/cpu-management/){
    found=1
  }
  next
}
{
  print
}
/rover/ && !found{
  print "- cpu-management:" val
}
' Input_file  Input_file

For your shown samples output will be as follows:

Ranges:
- PeakK2:8.8.9
- rover-heal:3.3.1
- cpu-management:1.9.0
Arg: V1
change: 1

Explanation: Adding detailed explanation for above.

awk -v val="${version}"         ##Starting awk program from here.
FNR==NR{                        ##Checking condition FNR==NR which will be treu when 1st time Input_file is being read.
  if($0~/cpu-management/){      ##Checking condition if line contains cpu-management then do following.
    found=1                     ##Setting found to 1 here.
  }
  next                          ##next will skip all further statements from here.
}
/rover/ && found==""{           ##Checking if line has rover AND found is NULL then do following.
  print $0 ORS "- cpu-management:" val ##Printing current line ORS with new value.
  next                          ##next will skip all further statements from here.
}
1                               ##Printing current line here.
' Input_file  Input_file        ##Mentioning Input_file name here.
like image 119
RavinderSingh13 Avatar answered Oct 27 '22 16:10

RavinderSingh13


Ignoring the detail about cpu-management already existing in the file (that doesn't seem to be a fundamental aspect of the question, and the provided solution already works for that), the classic sed solution for the replacement is to use a:

$ sed "/^- rover-heal/a\\                                         
- cpu-management:${version}
" input-file
Ranges:
- PeakK2:8.8.9
- rover-heal:3.3.1
- cpu-management:
Arg: V1
change: 1

If you're using bash, you can simplify the input with:

$ sed $'/^- rover-heal/a\\\n'"- cpu-management:$version"$'\n' input-file
Ranges:
- PeakK2:8.8.9
- rover-heal:3.3.1
- cpu-management:
Arg: V1
change: 1

Note that some sed allow you to skip the embedded new-line, but not all do.

like image 43
William Pursell Avatar answered Oct 27 '22 14:10

William Pursell


Assuming cpu-management should be checked only after rover-heal line:

$ version='1.9.0'
$ sed -E '/rover-heal/{$!N; /cpu-management/! s/\n|$/\n- cpu-management:'"${version}"'&/}' ip.txt
Ranges:
- PeakK2:8.8.9
- rover-heal:3.3.1
- cpu-management:1.9.0
Arg: V1
change: 1

This was tested on GNU sed, syntax might vary for other implementations.

  • /rover-heal/ line to be matched
    • $!N get another line, unless rover-heal is found on the last line of the input file
    • /cpu-management/! check if cpu-management is not present
      • \n|$ match newline or end of line and add details as needed

Use -i option for inplace editing.

like image 25
Sundeep Avatar answered Oct 27 '22 16:10

Sundeep