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.
 
You have to write only one ‑e command. sed(1) does not accept multiple commands via the ‑e parameter.
Why do you say that?
-e option works as documented, each instance appends more sed commands.

Of course, tOsYZYny 's original command did not make sense because the first sed command would ensure that the second would not match anything.
 
Why do you say that?
-e option works as documented, each instance appends more sed commands.

Of course, tOsYZYny 's original command did not make sense because the first sed command would ensure that the second would not match anything.
Are you sure?

My sed command worked, but it was just clumsy.
 
Back
Top