0

I feel I am close to solving this, but can't quite get there.

I have a script that searches to see if a utility is called in /etc/rc.local. If it isn't, I want to add a line calling it to the line just before exit 0 at the end of the file. So far, I have this:

sudo sed -i 's/.*exit 0.*/'$UTILITY_PATH'\n&/' /etc/rc.local

This kind of works, but also matches lines with "exit 0" as a comment - which occurs further up /etc/rc.local as a reminder to users to ensure that the script should end with this line.

So, to be clear, the following should match:

exit 0
 exit 0
exit   0   

and so forth. The following should NOT match:

#exit 0
#     exit 0
#   blah blah "exit 0" blah blah
# exit    0

Can anyone point me in the right direction?

stefandz
  • 60
  • 11
  • many things to take in mind and many possible outcomes, the best way would be to make the search more specific. one option could be to make your exit like: `exit 0`; and search specifficaly for that – Sir. Hedgehog Jun 20 '16 at 14:42
  • @hedgehog I don't have control over the format of the file - it may be user edited and all of those forms of exit 0 are valid to bash – stefandz Jun 20 '16 at 14:43
  • 1
    How about `exit` alone (which depends on the status of the last command) or `exit $((0))` or `x=exit; $x 0` or… – gniourf_gniourf Jun 20 '16 at 14:53

3 Answers3

3

This is a question about regular expressions, right? What you want is a match for exit 0 unless it's preceded by a #. What about this?

sudo sed -i 's/^[^#]*exit 0.*/'$UTILITY_PATH'\n&/' /etc/rc.local
wallenborn
  • 4,158
  • 23
  • 39
2

I guess you want this:

sed -r -i 's/^\s*exit\s{1,}[0-9]/foo\n&/' /etc/rc.local

It matches exit [0-9] - having possibly space in front and in between.


Btw, you can also perform both, the search if the pattern is found and the possible insertion in one step using awk:

awk '/foo/{m=1}/^\s*exit\s+[[:digit:]]/&&!m{print "foo"}1' /etc/rc.local

Newer versions of GNU awk also support in place editing:

awk -i inplace '/foo/{m=1}/^\s*exit\s+[[:digit:]]/&&!m{print "foo"}1' /etc/rc.local
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • because he wants to take in mind that this could exists in a comment as well or as text... – Sir. Hedgehog Jun 20 '16 at 14:47
  • This doesn't seem to work - it still matches the commented-out "exit 0" further up in rc.local – stefandz Jun 20 '16 at 14:49
  • @stefandz Sorry, I missed to anchor the pattern at the begin of the line using `^`. Added that. – hek2mgl Jun 20 '16 at 14:52
  • This works very well now and is general enough to allow for modification by others for various situations (including those pointed out by @gniourf_gniourf above. – stefandz Jun 20 '16 at 15:03
  • 1
    Oh, and thanks for the awk tip - I need to keep the search and replace separate for this, but might play with it in future. Really need to up my regex game... – stefandz Jun 20 '16 at 15:07
0

do you have '#' in middle of lane? bcaus if '#' is the first printable character you are in very easy spot: use one more regex (which is very simple here) to determine scope of sed operation just smth like this:

sed '/^\W*#/ ! s/something_u_want/whatever_u_want/ ' /etc/rc.local

/^\W*#/ means that sed will apply only for lines mathing this reg-ex, nothing will be done otherwise
and exclamation is just negation so conditions are reversed - now sed will apply only for these lines which DOESNT start from '#'

if # isnt first then... hmmm... maybe:

sed '/^[^#]*exit 0/ s/something_u_want/whatever_u_want/ ' /etc/rc.local
Neto
  • 21
  • 2