Find and replace text in files with the silver searcher and sed - sed

Heck I just can't remember ... I recently had a cool way to use ag with sed to do find and replace. The gist was simple, something like:
ag foo -l | ... magic here ... sed 's/foo/bar/g'
That doesn't work, but you might just know what does. Thanks!
PS. Three cheers for the Silver Searcher.

xargs is the magic you are looking for:
ag -l 'foo'|xargs sed -i 's/foo/abcd/g'

Related

sed command for text selection with starting and stopping phrase

I know the typical sed editing statements, such as
sed "s/substitutethis/withthis/g" file
However, when I searched for how to extract lines between two phrases, I found this:
sed -n "/startphrase/,/stopphrase/p" file
Could someone explain, please? The man page does not help me.
I know that -n suppresses echoing of output. Why do they use -n and p? Leaving out both does not work. What does the comma stand for?
This:
"/startphrase/,/stopphrase/p"
means "from the line containing startphrase to the line containing stopphrase, print".
There are many sed tutorials that talk about "range of lines".

Find and replace wildcard that spans across lines?

I would like to input some text like this:
foo
stuff
various stuff
could be anything here
variable number of lines
bar
Stuff I want to keep
More stuff I want to Keep
These line breaks are important
and get out this:
foo
teststuff
bar
Stuff I want to keep
More stuff I want to Keep
These line breaks are important
So far I've read and messed around with using sed, grep, and pcregrep and not been able to make it work. It looks like I could probably do such a thing with Vim, but I've never used Vim before and it looks like a royal pain.
Stuff I've tried includes:
sed -e s/foo.*bar/teststuff/g -i file.txt
and
pcregrep -M 'foo\s+bar\s' file.txt | xargs sed 's/foo.*bar/teststuff/g'
I'm not sure if it's just that I'm not using these commands correctly, or if I'm using the wrong tool. It's hard for me to believe that there is no way to use the terminal to find and replace wildcards that span lines.
For clarity, simplicity, robustness, maintainability, portability and most other desirable qualities of software, just use awk:
$ awk 'f&&/bar/{print "teststuff";f=0} !f; /foo/{f=1}' file
foo
teststuff
bar
Stuff I want to keep
More stuff I want to Keep
These line breaks are important
Try this with GNU sed:
sed -e '/^foo/,/^bar/{/^foo/b;/^bar/{i teststuff' -e 'b};d}'
See: man sed
This might work for you (GNU sed):
sed '/foo/,/bar/cteststuff' file
This will replace everything between foo and bar with teststuff.
However what you appear to want is everything following foo before bar, perhaps:
sed '/foo/,/bar/cfoo\nteststuff\nbar' file

One-liners to remove lines in which a specific character appears more than x times

I think the title says it all, I'm looking for a one-liner to remove lines of a file in which a specific character, let's say /, appears more than x times - 5, for instance.
Start:
/Bo/byl/apointe
S/ta/ck/ov/er/flo/w
M/oon/
Expected result:
/Bo/byl/apointe
M/oon/
Thank you for your suggestions !
You can use gsub function of awk. gsub return number of successful substitution made. So you can use that as reference to identify number of occurrences of particular character.
awk 'gsub(/\//,"&")<5' file
Updated Based on Ed Morton's suggestion.
This might work for you (GNU sed):
sed 's|/|&|5;T;d' file
All you need is:
awk -F/ 'NF<6' file
Look:
$ cat file
/Bo/byl/apointe
S/ta/ck/ov/er/flo/w
M/oon/
$ awk -F/ 'NF<6' file
/Bo/byl/apointe
M/oon/
I believe sed would be sufficient here. You'll want to look into //d and supply the correct condition. I'm going to try something and update when I have better ideas, you should too :)
Once you find it sed -i /{blah}/d will be enough to change it in the file, but you might want to run it without the -i and pipe it through less first to confirm it's doing what you think it's doing.
This would do :
sed -r '/(\/.*){5}\//d' file

Remove a hyphen from a specific line in a file

I have a data file that needs to have several uniq identifiers stripped of hyphens.
So I have:
(Special_Section "data-values")
and I want to have it replaced with:
(Special_Section "datavalues")
I wanted to use a simple sed find/replace, but the data and values are different each time. Preferably, I'd run this in-place since the file has a lot of other information I want to keep in tact.
Does sed or awk have a way to remove the hyphen from the matched portion only?
Currently I can match with: sed -i 's/Special_Section "[a-zA-Z0-9]*-[a-zA-Z0-9]*"/&/g *myfiles*
But I would like to then run s/-// on & if it's possible.
You seems to be using GNU sed, so something like this might work:
sed -ri '
s/(Special_Section [^-]*)-([^)]*)/\1\2/g
' <your_filename_glob>
does this work?
sed -i '/(Special_Section ".*-.*")/{s/-//}' yourFile
Close - scan for the lines and then substitute on those that match:
sed -i '/Special_Section "[a-zA-Z0-9]*-[a-zA-Z0-9]*"/s/\( "[a-zA-Z0-9]*\)-\([a-zA-Z0-9]*\)"/\1\2/' *myfiles*
You can split that over several lines to avoid the scroll bar in SO:
sed -i '/Special_Section "[a-zA-Z0-9]*-[a-zA-Z0-9]*"/{
s/\( "[a-zA-Z0-9]*\)-\([a-zA-Z0-9]*\)"/\1\2/
}' *myfiles*
And on further thoughts, you can also do:
sed -i 's/\(Special_Section "[a-zA-Z0-9]*\)-\([a-zA-Z0-9]*"\)/\1\2/' *myfiles*
This is more compact. You can add the g qualifier if you need it. Both solutions use the special \(...\) notation to capture parts of the regular expression.

How to globally replace strings in lines NOT starting with a certain pattern

I want to globally replace the string foo with the string bar, using sed. This should only be done for lines which do NOT start with the string ##Input.
I can't get it to work. I tried things like this but reached a point where I'm not sure if I know what I'm doing:
sed -i '/^##Input/ s/foo/bar/g' myfile
Please help!
You just need to negate the match using !:
sed -i '/^##Input/! s/foo/bar/g' myfile
You got to escape # as in \#.
An ugly answer for an ugly request (i.e. they get what they asked for):
echo \{
for file in *.json; do
sed -n '/^[\{\}]/! s/\([^\,]\)$/\1,/; /^[\{\}]/!p' $file
done
echo \{