how to delete a line from a file matching a particular pattern - sed

I have a file raw-vobs-config-spec which has these lines,
element /vob/ccm_tpl/repository/open_source/opensso_policy_agt/tomcat-v6/3_0-ER2/... VERSION_04
element /vob/ccm_tpl/repository/open_source/opensso/8_0_build6/... VERSION_01
element /vob/ccm_tpl/repository/open_source/commons_beanutils/1_8_2/... TPLBASE
#element /vob/ccm_tpl/repository/open_source/commons_collections/3_2_2/... TPLBASE
element /vob/ccm_tpl/repository/open_source/commons_collections/3_2_2/... /main/LATEST
element /vob/ccm_tpl/repository/open_source/commons_collections/3_2_2/... /CHECKEDOUT
element /vob/ccm_tpl/repository/open_source/commons_digester/1_8_1/... TPLBASE
element /vob/ccm_tpl/repository/open_source/commons_el/1_0/... TPLBASE
element /vob/ccm_tpl/repository/open_source/commons_jexl/2_0/... TPLBASE
element /vob/ccm_tpl/repository/open_source/commons_scxml/0_9/... TPLBASE
How can I delete the lines?
element /vob/ccm_tpl/repository/open_source/commons_collections/3_2_2/... /main/LATEST
element /vob/ccm_tpl/repository/open_source/commons_collections/3_2_2/... /CHECKEDOUT
and uncomment this line
#element /vob/ccm_tpl/repository/open_source/commons_collections/3_2_2/... TPLBASE
I tried,
sed -i '/patter/d' filename
but it is not working.

One fast way to delete lines from a file is to use the -n option in conjunction with a negated pattern:
Print lines that do not match the pattern
sed -n '/pattern/!p'
For example:
$ cat foo
foo
bar
baz
$ sed -n '/^b/!p' foo
foo
As for uncommenting, just drop a leading # (after Ed Morton's suggestion):
sed 's/^#//'
Example with the above file:
$ sed 's/^b//' foo
foo
ar
az

Related

sed line matching with exclamation

I am trying to understand this sed line matching part. What does it do exactly. The patters is supposed to match comment lines starting with ## and attempt to remove the comment characterrs at the front of the line.
pn_ere="^[[:space:]]*([#;!]+|#c|${cmt})[[:space:]]+"
sed -E -n "
/$beg_ere/ {
:L1
n
/$end_ere/z
/$pn_ere/!z
s/// ; p
tL1
}
"

sed to match first pattern among multiple matches

So for a given text like
a[test] asdfasdf [sdfsdf]b
I want the first match of text which is inside the first square brackets (regex = [.*]), so in this case [test].
I tried the following command it didn't work:
echo "a[test] asdfasdf [sdfsdf]b" | sed -n -e 's/.*\(\[.*\]\).*/\1/p'
This is returning [sdfsdf]
How do I get [test] instead ?
.* will select the longest match. Use [^[]* and [^]]* instead.
sed -n -e 's/[^[]*\(\[[^]]*\]\).*/\1/p'

replace text only in clause determinated by keywork

I want to processes text in some files that sometime expression exist in one line and sometime in multiple line
for example in multiple line
myfunc(param1,
param2,
param3);
or in one line
myfunc(param1, param2, param3);
does exist way that sed processes text only between myfunc and ;? keywords
at first step this help to me to port all multiple line to a line. Then I can to do my manupulation one a line type
if this possible?
Sed is for simple substitutions on individual lines, that is all. For anything even slightly more interesting you should be using awk. Something like this is probably what you want:
$ cat file
myfunc(param1,
param2,
param3);
myfunc(param1, param2, param3);
$ cat tst.awk
/myfunc/ { buf=""; inBlock=1 }
inBlock {
buf = (buf==""?"":buf RS) $0
if (/;/) {
$0 = buf
sub(/param2/,"lets have a tea party")
inBlock = 0
}
}
!inBlock
$ awk -f tst.awk file
myfunc(param1,
lets have a tea party,
param3);
myfunc(param1, lets have a tea party, param3);
Just replace the sub(/param2/,"lets have a tea party") line with whatever it is you really want to do with that block of text between myfunc and ;.
You can use the following sed script:
extract.sed:
# Check for "my"
/\bmy\b/ {
# Replace everything in front of
# my (including it)
s/.*\bmy\b//
# Define a label "a"
:a
# If the line does not contain "processes"
/\bprocesses\b/!{
# Get the next line of input and append
# it to the pattern buffer
N
# Branch back to label "a"
ba
}
# Replace "processes" and everything after it
s/\bprocesses\b.*//
# Print the pattern buffer
p
}
Call it like this:
sed -nf extract.sed input.txt

sed editing multiple lines

Sed editing is always a new challenge to me when it comes to multiple line editing. In this case I have the following pattern:
RECORD 4,4 ,5,48 ,7,310 ,10,214608 ,12,199.2 ,13,-19.2 ,15,-83 ,17,35 \
,18,0.8 ,21,35 ,22,31.7 ,23,150 ,24,0.8 ,25,150 ,26,0.8 ,28,25 ,29,6 \
,30,1200 ,31,1 ,32,0.2 ,33,15 ,36,0.4 ,37,1 ,39,1.1 ,41,4 ,80,2 \
,82,1000 ,84,1 ,85,1
which I want to convert into:
#RECORD 4,4 ,5,48 ,7,310 ,10,214608 ,12,199.2 ,13,-19.2 ,15,-83 ,17,35 \
# ,18,0.8 ,21,35 ,22,31.7 ,23,150 ,24,0.8 ,25,150 ,26,0.8 ,28,25 ,29,6\
# ,30,1200 ,31,1 ,32,0.2 ,33,15 ,36,0.4 ,37,1 ,39,1.1 ,41,4 ,80,2 \
# ,82,1000 ,84,1 ,85,1
Besides this I would like to preserve the entirety of these 4 lines (which may be more or less than 4 (unpredictable as the appear in the input) into one (long) line without the backslashes or line wraps.
Two tasks in one so to say.
sed is mandatory.
It's not terribly clear how you recognize the blocks you want to comment out, so I'll use blocks from a line that starts with RECORD and process as long as there are backslashes at the end (if your requirements differ, the patterns used will need to be amended accordingly).
For that, you could use
sed '/^RECORD/ { :a /\\$/ { N; ba }; s/[[:space:]]*\\\n[[:space:]]*/ /g; s/^/#/ }' filename
This works as follows:
/^RECORD/ { # if you find a line that starts with
# RECORD:
:a # jump label for looping
/\\$/ { # while there's a backslash at the end
# of the pattern space
N # fetch the next line
ba # loop.
}
# After you got the whole block:
s/[[:space:]]*\\\n[[:space:]]*/ /g # remove backslashes, newlines, spaces
# at the end, beginning of lines
s/^/#/ # and put a comment sign at the
# beginning.
}
Addendum: To keep the line structure intact, instead use
sed '/^RECORD/ { :a /\\$/ { N; ba }; s/\(^\|\n\)/&#/g }' filename
This works pretty much the same way, except the newline-removal is removed, and the comment signs are inserted after every line break (and once at the beginning).
Addendum 2: To just put RECORD blocks onto a single line:
sed '/^RECORD/ { :a /\\$/ { N; ba }; s/[[:space:]]*\\\n[[:space:]]*/ /g }' filename
This is just the first script with the s/^/#/ bit removed.
Addendum 3: To isolate RECORD blocks while putting them onto a single line at the same time,
sed -n '/^RECORD/ { :a /\\$/ { N; ba }; s/[[:space:]]*\\\n[[:space:]]*/ /g; p }' filename
The -n flag suppresses the normal default printing action, and the p command replaces it for those lines that we want printed.
To write those records out to a file while commenting them out in the normal output at the same time,
sed -e '/^RECORD/ { :a /\\$/ { N; ba }; h; s/[[:space:]]*\\\n[[:space:]]*/ /g; w saved_records.txt' -e 'x; s/\(^\|\n\)/&#/g }' foo.txt
There's actually new stuff in this. Shortly annotated:
#!/bin/sed -f
/^RECORD/ {
:a
/\\$/ {
N
ba
}
# after assembling the lines
h # copy them to the hold buffer
s/[[:space:]]*\\\n[[:space:]]*/ /g # put everything on a line
w saved_records.txt # write that to saved_records.txt
x # swap the original lines back
s/\(^\|\n\)/&#/g # and insert comment signs
}
When specifying this code directly on the command line, it is necessary to split it into several -e options because the w command is not terminated by ;.
This problem does not arise when putting the code into a file of its own (say foo.sed) and running sed -f foo.sed filename instead. Or, for the advanced, putting a #!/bin/sed -f shebang on top of the file, chmod +xing it and just calling ./foo.sed filename.
Lastly, to edit the input file in-place and print the records to stdout, this could be amended as follows:
sed -i -e '/^RECORD/ { :a /\\$/ { N; ba }; h; s/[[:space:]]*\\\n[[:space:]]*/ /g; w /dev/stdout' -e 'x; s/\(^\|\n\)/&#/g }' filename
The new things here are the -i flag for inplace editing of the file, and to have /dev/stdout as target for the w command.
sed '/^RECORD.*\\$/,/[^\\]$/ s/^/#/
s/^RECORD.*/#&/' YourFile
After several remark of #Wintermute and more information from OP
Assuming:
line with RECORD at start are a trigger to modify the next lines
structure is the same (no line with \ with a RECORD line following directly or empty lines)
Explain:
take block of line starting with RECORD and ending with \
add # in front of each line
take line (so after ana eventual modification from earlier block that leave only RECORD line without \ at the end or line without record) and add a # at the start if starting with RECORD

Search for a particular multiline pattern using awk and sed

I want to read from the file /etc/lvm/lvm.conf and check for the below pattern that could span across multiple lines.
tags {
hosttags = 1
}
There could be as many white spaces between tags and {, { and hosttags and so forth. Also { could follow tags on the next line instead of being on the same line with it.
I'm planning to use awk and sed to do this.
While reading the file lvm.conf, it should skip empty lines and comments.
That I'm doing using.
data=$(awk < cat `cat /etc/lvm/lvm.conf`
/^#/ { next }
/^[[:space:]]*#/ { next }
/^[[:space:]]*$/ { next }
.
.
How can I use sed to find the pattern I described above?
Are you looking for something like this
sed -n '/{/,/}/p' input
i.e. print lines between tokens (inclusive)?
To delete lines containing # and empty lines or lines containing only whitespace, use
sed -n '/{/,/}/p' input | sed '/#/d' | sed '/^[ ]*$/d'
space and a tab--^
update
If empty lines are just empty lines (no ws), the above can be shortened to
sed -e '/#/d' -e '/^$/d' input
update2
To check if the pattern tags {... is present in file, use
$ tr -d '\n' < input | grep -o 'tags\s*{[^}]*}'
tags { hosttags = 1# this is a comment}
The tr part above removes all newlines, i.e. makes everything into one single line (will work great if the file isn't to large) and then search for the tags pattern and outputs all matches.
The return code from grep will be 0 is pattern was found, 1 if not.
Return code is stored in variable $?. Or pipe the above to wc -l to get the number of matches found.
update3
regex for searcing for tags { hosttags=1 } with any number of ws anywhere
'tags\s*{\s*hosttags\s*=\s*1*[^}]*}'
try this line:
awk '/^\s*#|^\s*$/{next}1' /etc/lvm/lvm.conf
One could try preprocessing the file first, removing commments and empty lines and introducing empty lines behind the closing curly brace for easy processing with the second awk.
awk 'NF && $1!~/^#/{print; if(/}/) print x}' file | awk '/pattern/' RS=