sed - how to replace first word in line and preserve indents? - sed

For all lines that have .to I want to add expect( at the start.
For example for
blob.to 20
leave me
Thing.to(30)
Other.to {all}
leave me tooo
far_in.to stuff
I would like to see:
expect(blob.to 20
leave me
expect(Thing.to(30)
expect(Other.to {all}
leave me tooo
expect(far_in.to stuff
Currently I have:
sed -i '/.to/s/^[[:space]]*/expect(/' ../_spec_seded/"$file"
but am getting sed: -e expression #1, char 28: unterminateds' command`
from it
How do I resolve the error which I don't see yet and also 'preserve' spaces when doing this kind of substitution.
Bonus appreciation if you can exclude lines that have }.to instead of [any character except '}'].to
n.b. I deal with closing the parens separately.
p.s. unix site down right now.

Your leading spaces vanish because you choose not to preserve those. You could say:
sed '/.to/ s/^\([[:space:]]*\)/\1expect(/' filename
Alternatively, you could say:
sed '/\.to/ s/\(\S\)/expect(\1/' filename
For your input, it'd result in:
expect(blob.to 20
leave me
expect(Thing.to(30)
expect(Other.to {all}
leave me tooo
expect(far_in.to stuff
Bonus appreciation if you can exclude lines that have }.to instead of
[any character except '}'].to
If I understand it correct, you want to say:
sed '/[^}]\.to/ s/\(\S\)/expect(\1/' filename

This might work for you (GNU sed):
sed 's/\S\+\.to/expect(&/' file

Related

sed is ignoring some matches

I'm trying to replace all matches of http to https using backreference:
example test3.txt file:
http://stronka.wpblog.internal http://stronka.wpblog.internal
abc
jdfgijdf dfijog http://stronka.wpblog.internal dfgtdgrtg http://stronka.wpblog.internal/ sfdgth http://stronka.wpblog.internal/dupa drgfthj
ghj gjerioghj fhjdf http://stronka.wpblog.internal/
and when I run sed against the test3.txt file:
~# sed -r 's#http(://.*.wpblog.internal)#https\1#g' test3.txt
https://stronka.wpblog.internal http://stronka.wpblog.internal
abc
jdfgijdf dfijog https://stronka.wpblog.internal dfgtdgrtg https://stronka.wpblog.internal/ sfdgth http://stronka.wpblog.internal/dupa drgfthj
ghj gjerioghj fhjdf https://stronka.wpblog.internal/
Line 1 second link remains unchanged, line 2 third link remains unchanged, I'm lost, how could I tell sed to replace everything that is matching?
Because the .* wildcard is greedy, i.e. it will consume as much as possible of the line.
The simplest solution by far is to not use a wildcard at all; then sed does precisely what you expect on the simple input you provided.
sed 's#http://#https://#g' test3.txt
(Nothing in this regex needs anything except bog-standard 1968 regex, so the -r option - or its Linux equivalent -E - is not necessary or useful here.)
If for some reason you want a wildcard, use one which doesn't match across URL boundaries. In your example data, spaces seem to separate distinct URLs, so we can match greedily as many non-space characters as possible:
sed -r 's#http(://[^ ]*\.wpblog\.internal)#https\1#g' test3.txt
(Notice also how we use \. to match literal dots.)
Modern regex dialects like Perl's have non-greedy wildcards, but even then, it's better to use a regex which actually means what you want.
Try below:
sed -r 's/\bhttp\b/https/g'
\b is used to set boundaries around "http"
Based on the replies I've replaced the greedy wildcard .*:
sed -E 's#http(://[a-zA-Z0-9.-]*\.wpblog\.internal)#https\1#g'
And it's working as it should now, thank you all!

Why is my sed multiline find-and-replace not working as expected?

I have a simple sed command that I am using to replace everything between (and including) //thistest.com-- and --thistest.com with nothing (remove the block all together):
sudo sed -i "s#//thistest\.com--.*--thistest\.com##g" my.file
The contents of my.file are:
//thistest.com--
zone "awebsite.com" {
type master;
file "some.stuff.com.hosts";
};
//--thistest.com
As I am using # as my delimiter for the regex, I don't need to escape the / characters. I am also properly (I think) escaping the . in .com. So I don't see exactly what is failing.
Why isn't the entire block being replaced?
You have two problems:
Sed doesn't do multiline pattern matches—at least, not the way you're expecting it to. However, you can use multiline addresses as an alternative.
Depending on your version of sed, you may need to escape alternate delimiters, especially if you aren't using them solely as part of a substitution expression.
So, the following will work with your posted corpus in both GNU and BSD flavors:
sed '\#^//thistest\.com--#, \#^//--thistest\.com# d' /tmp/corpus
Note that in this version, we tell sed to match all lines between (and including) the two patterns. The opening delimiter of each address pattern is properly escaped. The command has also been changed to d for delete instead of s for substitute, and some whitespace was added for readability.
I've also chosen to anchor the address patterns to the start of each line. You may or may not find that helpful with this specific corpus, but it's generally wise to do so when you can, and doesn't seem to hurt your use case.
# separation by line with 1 s//
sed -n -e 'H;${x;s#^\(.\)\(.*\)\1//thistest.com--.*\1//--thistest.com#\2#;p}' YourFile
# separation by line with address pattern
sed -e '\#//thistest.com--#,\#//--thistest.com# d' YourFile
# separation only by char (could be CR, CR/LF, ";" or "oneline") with s//
sed -n -e '1h;1!H;${x;s#//thistest.com--.*\1//--thistest.com##;p}' YourFile
Note:
assuming there is only 1 section thistest per file (if not, it remove anything between the first opening until the last closing section) for the use of s//
does not suite for huge file (load entire file into memory) with s//
sed using addresses pattern cannot select section on the same line, it search 1st pattern to start, and a following line to stop but very efficient on big file and/or multisection

Using sed to comment out lines that contain a specific string of text

Please bear with me as I'm new to the forums and tried to do my research before posting this. What I'm trying to do is to use sed to look through multiple lines of a file and any line that contains the words 'CPU Usage" I want it to comment out that line and also 19 lines immediately after that.
Example file.txt
This is some random text CPU USAGE more random text
Line2
Line3
Line4
Line5
etc.
I want sed to find the string of text CPU usage and comment out the line and the 19 lines following
#This is some random text CPU USAGE more random text
#Line2
#Line3
#Line4
#Line5
#etc.
This is what I've been trying but obviously it is not working since I'm posting on here asking for help
sed '/\/(CPU Usage)s/^/#/+18 > File_name
sed: -e expression #1, char 17: unknown command: `^'
I'd like to be able to use this on multiple files. Any help you can provide is much appreciated!
GNU sed has a non-standard extension (okay, it has many non-standard extensions, but there's one that's relevant here) of permitting /pattern/,+N to mean from the line matching pattern to that line plus N.
I'm not quite sure what you expected your sed command to do with the \/ part of the pattern, and you're missing a single quote in what you show, but this does the trick:
sed '/CPU Usage/,+19 s/^/#/'
If you want to overwrite the original files, add -i .bak (or just -i if you don't mind losing your originals).
If you don't have GNU sed, now might be a good time to install it.
This can easily be done with awk
awk '/CPU Usage/ {f=20} f && f-- {$0="#"$0}1' file
When CPU Usage is found, set flag f=20
If flag f is true, decrements until 0 and for every time, add # in front of the line and print it.
Think this should work, cant test it, if anyone finds something wrong just let me know :)
awk '/CPU Usage/{t=1}t{x++;$0="#"$0}x==19{t=0;x=0}1' file

Matching strings even if they start with white spaces in SED

I'm having issues matching strings even if they start with any number of white spaces. It's been very little time since I started using regular expressions, so I need some help
Here is an example. I have a file (file.txt) that contains two lines
#String1='Test One'
String1='Test Two'
Im trying to change the value for the second line, without affecting line 1 so I used this
sed -i "s|String1=.*$|String1='Test Three'|g"
This changes the values for both lines. How can I make sed change only the value of the second string?
Thank you
With gnu sed, you match spaces using \s, while other sed implementations usually work with the [[:space:]] character class. So, pick one of these:
sed 's/^\s*AWord/AnotherWord/'
sed 's/^[[:space:]]*AWord/AnotherWord/'
Since you're using -i, I assume GNU sed. Either way, you probably shouldn't retype your word, as that introduces the chance of a typo. I'd go with:
sed -i "s/^\(\s*String1=\).*/\1'New Value'/" file
Move the \s* outside of the parens if you don't want to preserve the leading whitespace.
There are a couple of solutions you could use to go about your problem
If you want to ignore lines that begin with a comment character such as '#' you could use something like this:
sed -i "/^\s*#/! s|String1=.*$|String1='Test Three'|g" file.txt
which will only operate on lines that do not match the regular expression /.../! that begins ^ with optional whiltespace\s* followed by an octothorp #
The other option is to include the characters before 'String' as part of the substitution. Doing it this way means you'll need to capture \(...\) the group to include it in the output with \1
sed -i "s|^\(\s*\)String1=.*$|\1String1='Test Four'|g" file.txt
With GNU sed, try:
sed -i "s|^\s*String1=.*$|String1='Test Three'|" file
or
sed -i "/^\s*String1=/s/=.*/='Test Three'/" file
Using awk you could do:
awk '/String1/ && f++ {$2="Test Three"}1' FS=\' OFS=\' file
#String1='Test One'
String1='Test Three'
It will ignore first hits of string1 since f is not true.

Use Sed to modify a line that has an initial space and contains a comma

This should be extremely simple, but for the life of me I just can't get gnu-sed to do it this afternoon.
The file in question has lines that look like this:
PART NUMBER PART NUMBER QUANTITY WEIGHT -999 -4,999 -9,999
w/ UL APPROVAL
MIN-3
I need to prepend every line like the "MIN-3" line with a ">" character, and the only thing specifically differentiating those lines from the others are two things:
The first character is a space " ".
The lines do not contain a comma.
I've tried mostly things like any of the following:
/^ +[^,]+$/ s/^/>/
/^ +[\w\-]+$/ s/^/>/
/^ +(\w|\-)+$/ s/^/>/
I will admit, I am somewhat new to sed. :)
Edit: Answers that use perl, or awk could also be appreciated, though my initial target is sed.
try this:
sed '/^ [^,]*$/s/^/>/'
the output is, only the line with MIN-3 with leading >
sed default uses basic regex. so the + should be \+ in your script. I think that could be the problem killing your time. You could add -r however, to let sed use extended-regex.
According to your description this should do:
sed 's/^\([ ][^,]*\)$/> \1/' input
which matches the complete line if the line starts with a space and then contains anything but a comma until the end.
Here is a simple answer:
sed 's/^ [^,]*$/>&/'