1

I do wish to modify a Mac OS X sandbox file via a one-line (copy and paste) command, by inserting a new line — containing a regex — after a line that contains a specific string (also being a regex pattern).

The file to edit requires root rights and is located at /usr/share/sandbox/clamd.sb.

Both search and append lines contain loads of usually to be escaped characters because these are regex-es and containing paths.

Search for line containing

(regex #"^/private/var/clamav/")

Note: the string is preceded with tabs in one case.

Insert this line before the match

    (regex #"^/System/Library/PrivateFrameworks/TrustEvaluationAgent.framework/Versions/A/TrustEvaluationAgent\$")

Note: this to be inserted new-line-string should be prepended with one tab (\t).

My failing try

sudo sed -i '' -e $'/(regex #"\^\/private\/var\/clamav\/")/a \t(regex #"\^\/System\/Library\/PrivateFrameworks\/TrustEvaluationAgent\.framework\/Versions\/A\/TrustEvaluationAgent\\\$")' /usr/share/sandbox/clamd.sb
sed: 1: "/(regex #"\^\/private\/ ...": command a expects \ followed by text

Question

How to fix the above sed command

or

supply a better readable and working alternative that can be used to copy from a website and paste into the Mac OS X terminal (bash) to extend this sandbox configuration file?

  • 1
    1) You need i to insert before the match, not a. 2) Avoid picket fence (i.e. use a delimiter like | - keep in mind that in a context address you have to escape the first one). 3) With i or a you only need to escape backslashes and the end of lines (except the last one): sed -e '\|(regex #"^/private/var/clamav/")|i\' -e ' (regex #"^/System/Library/PrivateFrameworks/TrustEvaluationAgent.framework/Versions/A/TrustEvaluationAgent\\$")' the leading space in the second expression is a literal tab. – don_crissti Oct 27 '16 at 22:05
  • 1
    Don't use -i '' until you're sure your command is correct. -i is for in-place editing, not for testing your command. :) – Wildcard Oct 27 '16 at 22:07
  • 1
    @don_crissti, macOS Sed will strip out that leading tab character, so that command won't work exactly as requested. – Wildcard Oct 28 '16 at 1:28
  • see if this works out.. seq 4 | sed '/3/ s/.*/ abc\n&/' ... replace /3/ with appropriate search pattern and ` abc` with line to insert before matching line – Sundeep Oct 28 '16 at 5:08
  • @Wildcard - yeah, I left a comment about this on your Q - I still think it's doable with i or a but anyway, even if it wasn't, imo it's still easier to run sed '\|(regex #"^/private/var/clamav/")|s|^| (regex #"^/System/Library/PrivateFrameworks/TrustEvaluationAgent.fr‌​amework/Versions/A/T‌​rustEvaluationAgent\‌​\$")\n&|' (replacing the n in \n with a literal newline) - similar to what Sundeep suggests above - than doing all that escaping with awk... – don_crissti Oct 28 '16 at 12:25
1

You can't do this with macOS Sed, because it strips leading whitespace from the lines that you are inserting.

Using Awk:

awk '/\(regex #"\^\/private\/var\/clamav\/"\)/ {print "\t(regex #\"^/System/Library/PrivateFrameworks/TrustEvaluationAgent.framework/Versions/A/TrustEvaluationAgent\$\")"}; {print}' /usr/share/sandbox/clamd.sb > ~/temp-clamd.sb

Note that I've redirected the output to ~/temp-clamd.sb rather than editing the file in place (which is tricky or impossible with BSD Awk).

Next you can check that the changes are as you expect with:

diff /usr/share/sandbox/clamd.sb ~/temp-clamd.sb

If everything is correct, overwrite the contents of the original file with the modified copy (don't use mv, which would change the inode, permissions, owner):

cat ~/temp-clamd.sb | sudo tee /usr/share/sandbox/clamd.sb
  • The awk result is that the diff is not able to find any difference between /usr/share/sandbox/clamd.sb and ~/temp-clamd.sb. The sed is ok, except for the minor issue that the <tab> \t is not inserted. The new line directly starts with (regex. – Pro Backup Oct 28 '16 at 0:55
  • @ProBackup, see edit re Sed result. I got it on the Awk result; are you certain that line has no trailing whitespace or anything similar? Compare the results of grep -F "(regex #\"^/private/var/clamav/\")" /usr/share/sandbox/clamd.sb and grep -xF "(regex #\"^/private/var/clamav/\")" /usr/share/sandbox/clamd.sb; are they the same? (Do they both output a line?) – Wildcard Oct 28 '16 at 1:00
  • The first grep -F does output 1 line. The second grep -xF does not output a line. There doesn't seem to be a trailing whitespace character. – Pro Backup Oct 28 '16 at 1:17
  • @ProBackup, that means the line has leading or trailing space. (The -F means "fixed string comparison" rather than regex, and -x limits it to whole line matches.) Tweak the expression until it shows up with -xF as well as -F, and then drop that exact string into the Awk equality test. It's hard to tell from your comment formatting, but possibly " (regex #\"^/private/var/clamav/\")" is what you need (note the leading space at the beginning). – Wildcard Oct 28 '16 at 1:19
  • @mikeserv, not helpful. An Awk string equality check should work perfectly fine. The only trick is to ensure we have the full line in the equality check. – Wildcard Oct 28 '16 at 1:26

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.