How to use sed to remove some lines around the specified line? - sed

I want to remove a maven dependency in all the pom.xml files.
I know how to remove the line after the specified line but have no idea to remove the lines before the specified line.
<dependency>
<groupId>moon</groupId>
<artifactId>conup-remote-configuration</artifactId>
<version>0.9.1-DU-SNAPSHOT</version>
</dependency>

maybe you could process the file backwards, starting with the last line of the file and ending with the first line of the file. Something like tac myfile.txt | sed ... | tac myfile2.txt tac is cat backwards.

This will remove the line before the line with pattern hits.
awk '!/pattern/ && NR>1 {print f} {f=$0} END {print f}' file

Related

how to replace with sed when source contains $

I have a file that contains:
$conf['minified_version'] = 100;
I want to increment that 100 with sed, so I have this:
sed -r 's/(.*minified_version.*)([0-9]+)(.*)/echo "\1$((\2+1))\3"/ge'
The problem is that this strips the $conf from the original, along with any indentation spacing. What I have been able to figure out is that it's because it's trying to run:
echo " $conf['minified_version'] = $((100+1));"
so of course it's trying to replace the $conf with a variable which has no value.
Here is an awk version:
$ awk '/minified_version/{$3+=1} 1' file
$conf['minified_version'] = 101
This looks for lines that contain minified_version. Anytime such a line is found the third field, $3, is incremented by.
My suggested approach to this would be to have a file on-disk that contained nothing but the minified_version number. Then, incrementing that number would be as simple as:
minified_version=$(< minified_version)
printf '%s\n' "$(( minified_version + 1 ))" >minified_version
...and you could just put a sigil in your source file where that needs to be replaced. Let's say you have a file named foo.conf.in that contains:
$conf['minified_version'] = #MINIFIED_VERSION#
...then you could simply run, in your build process:
sed -e "s/#MINIFIED_VERSION#/$(<minified_version)/g" <foo.conf.in >foo.conf
This has the advantage that you never have code changing foo.conf.in, so you don't need to worry about bugs overwriting the file's contents. It also means that if you're checking your files into source control, so long as you only check in foo.conf.in and not foo.conf you avoid potential merge conflicts due to context near the version number changing.
Now, if you did want to do the native operation in-place, here's a somewhat overdesigned approach written in pure native bash (reading from infile and writing to outfile; just rename outfile back over infile when successful to make this an in-place replacement):
target='$conf['"'"'minified_version'"'"'] = '
suffix=';'
while IFS= read -r line; do
if [[ $line = "$target"* ]]; then
value=${line##*=}
value=${value%$suffix}
new_value=$(( value + 1 ))
printf '%s\n' "${target}${new_value}${suffix}"
else
printf '%s\n' "$line"
fi
done <infile >outfile

Replace period with dash via command line?

Here's my current command:
sed 's/\./-/' file.txt > CLEANED.txt
What I'm trying to do is replace all periods in my file with a dash. Some lines have multiple periods and I need all of them replaced with a dash - but the command above seems to just replace the first one in each line.
What am I doing wrong for it to not replace all of the periods?
In perl, just add the /g modifier to your regex:
perl -pe 's/\./-/g' file.txt > CLEANED.txt
Explanation:
Switches:
-p: Creates a while(<>){...; print} loop for each “line” in your input file.
-e: Tells perl to execute the code on command line.
Code:
s/\./-/g: Replace all periods with dashes. Could also use the transliteration operator: y/./-/
Add /g for a global replacement, else it only affects the first occurrence.
Like so:
sed 's/\./-/g' file.txt > CLEANED.txt

How do insert lines of text into file after a particular line in unix [duplicate]

This question already has answers here:
How do I add a line of text to the middle of a file using bash?
(6 answers)
Closed 10 years ago.
How do insert lines of text into file after a particular line in unix ?
Background: The file is an autogenerated textfile but I manually have to edit it every time it is regenerated to add in 4 additional lines after a particular line. I can gurantee that this line will always be in the file but I cannot guarantee excalty what line it will be on so I want the additional lines to be added on the basis of the position of this line rather than adding to a fixed rownumber. I want to automate this process as it is part of my build process.
I'm using Mac OSX so I can make use of unix comand line tools, but Im not very familiar with such tools and cannot work out how to do this.
EDIT
Thanks for the solution, although I havent managed to get them working yet:
I tried Sed solution
sed -i '/<string>1.0</string>/ a <key>CFBundleHelpBookFolder</key>\
<string>SongKongHelp</string>\
<key>CFBundleHelpBookName</key>\
<string>com.jthink.songkong.Help</string>
' /Applications/SongKong.app/Contents/Info.plist
but get error
sed: 1: "/Applications/SongKong. ...": invalid command code S
and I tried the bash solution
#!/bin/bash
while read line; do
echo "$line"
if [[ "$line" = "<string>1.0</string>"]]; then
cat mergefile.txt # or echo or printf your extra lines
fi
done < /Applications/SongKong.app/Contents/Info.plist
but got error
./buildosx4.sh: line 5: syntax error in conditional expression: unexpected token `;'
./buildosx4.sh: line 5: syntax error near `;'
./buildosx4.sh: line 5: ` if [[ "$line" = "<string>1.0</string>"]]; then'
EDIT 2
Now working, i was missing a space
#!/bin/bash
while read line; do
echo "$line"
if [[ "$line" = "<string>1.0</string>" ]]; then
cat mergefile.txt # or echo or printf your extra lines
fi
done < /Applications/SongKong.app/Contents/Info.plist
Assuming the marker line contains fnord and nothing else;
awk '1;/^fnord$/{print "foo"; print "bar";
print "baz"; print "quux"}' input >output
Another way to look at this is that you want to merge two files at some point in one of the files. If your extra four lines were in a separate file, you could make a more generic tool like this:
#!/usr/bin/awk
BEGIN {
SEARCH=ARGV[1]; # Get the search string from the command line
delete ARGV[1]; # Delete the argument, so subsequent arguments are files
}
# Collect the contents of the first file into a variable
NR==FNR {
ins=ins $0 "\n";
next;
}
1 # print every line in the second (or rather the non-first) file
# Once we're in the second file, if we see the match, print stuff...
$0==SEARCH {
printf("%s", ins); # Using printf instead of print to avoid the extra newline
next;
}
I've spelled this out for ease of documentation; you could obviously shorten it to something that looked more like triplee's answer. You'd invoke this like:
$ scriptname "Text to match" mergefile.txt origfile.txt > outputfile.txt
Done this way, you'd have a tool that could be used to achieve this kind of merge on different files and with different text.
Alternately, you could of course do this in pure bash.
#!/bin/bash
while read line; do
echo "$line"
if [[ "$line" = "matchtext" ]]; then
cat mergefile.txt # or echo or printf your extra lines
fi
done < origfile.txt
The problem can be solved efficiently for any filesize by this algorithm:
Read each line from the original file and print it to a tempfile.
If the last line was the marker line, print your insertion lines to the tempfile
Print the remaining lines
Rename the tempfile to the original filename.
As a Perl script:
#!perl
use strict; use warnings;
$^I = ".bak"; # create a backup file
while (<>) {
print;
last if /regex to determine if this is the line/;
}
print <<'END';
Yourstuff
END
print while <>; # print remaining lines
# renaming automatically done.
Testfile:
foo
bar
baz
qux
quux
Regex is /^ba/.
Usage: $ perl this_script.pl source-file
The testfile after processing:
foo
bar
Yourstuff
baz
qux
quux
use the sed 'a command with a regex for the line you need to match
sed -i '/the target line looks like this/ a this is line 1\
this is line 2\
this is line 3\
this is line 4
' FILENAME

Match a string, skip if it has a . (DOT) infront of the result

Here's what I use to match a string in a variable and delete the line where the match exists:
sed -i '/'"$domainAndSuffix.cfg"'/d' /etc/file
I'd like to know how to match a string in a variable, but if the match in the file has a . adjacent to it on the immediate left, then it will NOT delete this line and keep going through the file until it finds a match without a .
Sample file Contents:
happy.domain.com
pappy.domain.com
domain.com
String to match:
domain.com
Desired File Output:
happy.domain.com
pappy.domain.com
*Edit:
Actual File Contents:
cfg_file=/etc/nagios/objects/http_url/bob.ca.cfg
cfg_file=/etc/nagios/objects/http_url/therecord.com.cfg
cfg_file=/etc/nagios/objects/http_url/events.therecord.com.cfg
cfg_file=/etc/nagios/objects/http_url/read.therecord.com.cfg
cfg_file=/etc/nagios/objects/http_url/wheels.ca.cfg
cfg_file=/etc/nagios/objects/http_url/used-vehicle-search.autos.ca.msn.com.cfg
cfg_file=/etc/nagios/objects/http_url/womensweekendshow.com.cfg
cfg_file=/etc/nagios/objects/http_url/yorkregion.com.cfg
cfg_file=/etc/nagios/objects/http_url/yourclassifieds.ca.cfg
If the preceding substring is fixed, you can try the following:
PREFIX='cfg_file=\/etc\/nagios\/objects\/http_url\/'
DOMAIN='therecord.com'
sed -i "/^${PREFIX}${DOMAIN}/d" file
If it is not fixed, it would be nice to use a negative lookbehind, but sed can't do that. You can use ssed or GNU grep:
ssed -Ri '/(?<!\.)'"$DOMAIN"'.cfg/d' file
or
grep -vP '(?<!\.)'"$DOMAIN" > file1; mv file1 file

replace line with sed in csh

I am trying to change the content of a specific line in a batch of files. I thought that would be a piece of cake but for some reason, nothing happens, so I guess I am missing something.
Line 8 should have been replaced.
Here the csh script I used:
#!/bin/csh
#
# replace context in line xxx by yyy
# 2010/05/07
set files = `ls FILENAMEPART*`
echo $files
foreach file ($files)
sed '8,8 s/1/2 /' $file
end
thanks for suggestions
sed prints the resulting file (with the lines replaced) to stdout by default and leaves the source (input) file untouched. Use the -i option for in-place editing, which means that the changes are made directly in $file.