Shell Using sed to prefix a line, but only if it does not contain a pattern

I'm trying to simplify this sed expression as I think it is not the best way to represent what is going on. I have a sample shell script:

#!/bin/sh
lib include.sh
lib git:install/git.sh
lib git:git/include.sh
_git_init

cat /tmp/sample.sh | sed -e 's/^lib /lib git:install\//' -e 's/^lib git:install\/git:/lib git:/'

Is there a way to do this with a single sed expression, 1 -e?

So, line 2 shall become:
lib git:install/include.sh

And, the others shall remain as they were.
 
Yes, you're right about cat, my bad. That was a relic of my framework ... I'm running this after a find expression.

It might be a bad idea, but for the past 5 years, I've been working on a shell script framework so I can use the same cmds at work and home to do the same 'stuff'. If I program it in go or Java, that might be surely easier, but I wouldn't be able to use that at work.

Thanks for those references.
 
cat /tmp/sample.sh | sed -e 's/^lib /lib git:install\//' -e 's/^lib git:install\/git:/lib git:/'
[…] Is there a way to do this with a single sed expression, 1 -e?
You have to write only one ‑e command. sed(1) does not accept multiple commands via the ‑e parameter. Try reversing your commands:​
Bash:
sed -e 's/^lib /lib git:install\//' -e 's/^lib git:install\/git:/lib git:/' < /tmp/sample.sh
sed -e 's/^lib git:install\/git:/lib git:/' -e 's/^lib /lib git:install\//' < /tmp/sample.sh
They produce different results. Only the last ‑e is actually taken account of.​
Bash:
sed -E 's|^lib (git:install/git:)?|lib git:install/|' < /tmp/sample.sh # I ain’t sure what you want.
Use extended regular expressions (capital ‑E) and avoid escaping by using a different delimiter other than a forward slash.

PS: sed(1) understands multiple ‑e but evidently the order matters. So the question is: Do you want to edit the line multiple times?​
 
You have to write only one ‑e command. sed(1) does not accept multiple commands via the ‑e parameter. Try reversing your commands:​
Bash:
sed -e 's/^lib /lib git:install\//' -e 's/^lib git:install\/git:/lib git:/' < /tmp/sample.sh
sed -e 's/^lib git:install\/git:/lib git:/' -e 's/^lib /lib git:install\//' < /tmp/sample.sh
They produce different results. Only the last ‑e is actually taken account of.​
Bash:
sed -E 's|^lib (git:install/git:)?|lib git:install/|' < /tmp/sample.sh # I ain’t sure what you want.
Use extended regular expressions (capital ‑E) and avoid escaping by using a different delimiter other than a forward slash.

PS: sed(1) understands multiple ‑e but evidently the order matters. So the question is: Do you want to edit the line multiple times?​
Yes, I want to edit the line multiple times because in this case, what I'm doing is:

1. translate the "relative" import of lib include.sh to lib git:install/include.sh
2. translate remaining imports back to the original since I couldn't device a clever sed expression to ignore lines that already have git: on them
these imports first become "lib git:install/git:git.sh"
then, they get corrected to their original form "lib git:install/git.sh"
 
Is this your card?​
Bash:
sed -e 's|^lib \([^g][^i][^t][^:]\)|lib git:install/\1|' < /tmp/sample.sh # BRE
sed -E 's|^lib ([^g][^i][^t][^:])|lib git:install/\1|'   < /tmp/sample.sh # ERE

Nice, that works.

Now, that doesn't look terrible. I see the [^] hacks and I'm a bit split on that. I'm still pondering.

So, the question for me to decide is which style I prefer as both accomplish the same thing. Performance differences will be negligible here. I think this may be useful to have as a reference for more complicated use cases.
 
A variation to the solution provided by Kai Burghardt
So, line 2 shall become:

And, the others shall remain as they were.
I see the [^] hacks and I'm a bit split on that. I'm still pondering.
If I understand correctly, you want this behaviour:
sh:
$ cat sample.sh
#!/bin/sh
lib include.sh
lib git:install/git.sh
lib git:git/include.sh
_git_init

$ sed '/git:/! s/^lib /lib git:install\//' < sample.sh
#!/bin/sh
lib git:install/include.sh
lib git:install/git.sh
lib git:git/include.sh
_git_init

$
 
Yes.

I'm trying to digest that.

I have used the pattern matching syntax to delete lines, but this is new to me. If I understand correctly, the trailing !, means to invert that match, so:
1. must not contain git:
2. replace lines starting with 'lib ' with 'lib git:install/'

If so, then I think that is the solution I'm looking for because it is concise and easily explainable.
 
If I understand correctly, the trailing !, means to invert that match
Yes, you're correct. The address format: address command isn't explicitly explained in
https://www.grymoire.com/Unix/Sed.html and you have to really look for it in his Sed Reference Chart (pdf). sed(1):
Code:
       [2addr]!function
       [2addr]!function-list
	       Apply the function or function-list only	to the lines that  are
	       not selected by the address(es).
but these available options can be hard to find.
 
Back
Top