SED delete comments but leave specific negated comment strings - sed

I'm trying to delete comments from file but what's important I want to leave specific strings:
## Something
# START
# END
These has to stay with rest not commented lines and I want to remove rest with "d" - this is important. I don't want to use print negation or other tricks because this sed command also process another things later with additional "-e".
Here is sample file:
# START
group1: user1#domain.com, user2#domain.com, user3#domain.com
group2: user3#domain.com, user4#domain.com
# S
#STAR
# start
# star
# comment is here
## Owner1
group3: user1#domain.com, user3#domain.com
## Owner2
group4: user4#domain.com, user3#domain.com
group3: user2#domain.com, user3#domain.com
# END
group5: user4#domain.com
alias1: user6#domain.com
I tried to use command like:
sed -e '/^#[^#]/d' sample.file
Which remove each line starting with "#" and next character is NOT "#" so it leaves "##" lines but how to manage removing rest without loosing # START and # END lines?
I need to do this in same command without pipes, "!p" or "p" versions it has to be this "d" modified version.
Tried things like:
sed -e '/^#[^#][^S][^T][^A][^R][^T]/d'
or
sed -e '/^#[^#]\([^S][^T][^A][^R][^T]\|[^E][^N][^D]\)/d'
but nothing is working the way I want.
I'm not sure if this is possible this way.
Expected output:
# START
group1: user1#domain.com, user2#domain.com, user3#domain.com
group2: user3#domain.com, user4#domain.com
## Owner1
group3: user1#domain.com, user3#domain.com
## Owner2
group4: user4#domain.com, user3#domain.com
group3: user2#domain.com, user3#domain.com
# END
group5: user4#domain.com
alias1: user6#domain.com
Greetings & thanks for help :)

Try:
sed -E '/^##|^# START|^# END/bskip; /^#/d; :skip' file
Example
$ sed -E '/^##|^# START|^# END/bskip; /^#/d; :skip' file
# START
group1: user1#domain.com, user2#domain.com, user3#domain.com
group2: user3#domain.com, user4#domain.com
## Owner1
group3: user1#domain.com, user3#domain.com
## Owner2
group4: user4#domain.com, user3#domain.com
group3: user2#domain.com, user3#domain.com
# END
group5: user4#domain.com
alias1: user6#domain.com
How it works
/^##|^# START|^# END/bskip
For any line that matches ^## or ^# START or ^# END, we branch to the label skip.
/^#/d
For all other lines that start with #, we delete.
:skip
This defines the label skip.
BSD/macOS
The above was tested with GNU sed. For BSD/macOS sed, try:
sed -E -e '/^##|^# START|^# END/bskip' -e '/^#/d' -e ':skip' file

This is more verbose than John1024s answer, but works too:
sed -r 's/# ((START)|(END)).*/## \1/;/^#[^#].*/d;s/## ((START)|(END))/# \1/;' sample.conf
Transfer the # START/END comment to the protected ## format, then, do the transformation, then transform it to # START/END back.
First I've overseen the 'no-/p'-requierement, then the obvious solution is:
sed -r '/# (START)|(END).*/p;/^#[^#].*/d' sample.conf
Instead of deleting a complicated delete-pattern /d, you can use a simple print-pattern /p.
Note that [^S][^T][^A][^R][^T] would match "END" (with 2 trailing spaces - maybe unlikely, but if another 3- or 5-letter exception needs treatment, it gets ugly, if it isn't alread.

Related

Using sed, delete from specific line until first match(not included)

I have some data looks like
1:Alice 2313
2:Desctop 456
3:Cook 111
4:.filename 50
...
...
100:Good 3
Dir num:10
File num:90
...
...
I want to delete all lines from specific line(ex. line 3) until the line "Dir num:" show up.
The idea output should be(according above example):
1:Alice 2313
2:Desctop 456
Dir num:10
File num:90
...
...
I have google several solutions likesed -i '/somestring/,$!d' file.
But these solutions are not suitable because of the specific line where deletion satarting.
How can I do this in 1 command without any tmp file?
Forgive my poor English, I'm not native English speaker.
You need to specify the address range from the specified line number (3) to the line matching the pattern (/Dir num/). However, it's not quite as simple as
sed '3,/Dir num/ d' file
because that will delete the "Dir num" line. Try this instead:
sed '3,/Dir num/ {/Dir num/! d}' file
That will, for the lines in the range, check that the line does not match the pattern: is the pattern is not matched, delete it.
Use the range: /pattern1/,/pattern2/ option of sed
$ sed -e '/2:Desctop 456/,/Dir num:10/{//!d}' inputFile
1:Alice 2313
2:Desctop 456
Dir num:10
File num:90
...
...

In Bazaar (bzr), How to show log of only commits which were done in a specific branch nick?

In Mercurial (hg), a user can enter the following command --
hg log --branch branchName
This shows only the commits which were done against a specific named branch.
What bzr command can give me the same functionality? I could not find an option for "bzr log" that would do the same thing. For example, if I committed revs 1, 2, and 3 in branch nick "trunk" and 2.1.1, 2.1.2, and 4 in branch nick "ftr-foo", how can I print only the revs under branch nick "ftr-foo" such that I'd only see 2.1.1, 2.1.2, 4? And how would I get only the commits which were done against the "trunk" branch nick such that I'd only see 1, 2, and 3?
DAG graph below.
4 [ftr-foo]
| \
3 \ [trunk]
| \
| 2.1.2 [ftr-foo]
| |
| 2.1.1 [ftr-foo]
| /
| /
2 [trunk]
|
1 [trunk]
While Bzr has the basic machinery to allow matching commits by other criteria, this is still a non-trivial exercise in plugin writing. A simpler alternative is to filter the output of bzr log or bzr log -n0 through a grep-like program that understands where commits begin and end.
The following Python program (which should work with both Python 2.7 and Python 3.x) allows you to grep bzr log output for arbitrary regular expressions:
#!/usr/bin/env python
import sys, re, os
args = sys.argv[1:]
if not args or args in [["--help"], ["-h"], ["-help"]]:
prog = os.path.basename(sys.argv[0])
print("Usage: bzr log BZRARGS | " + prog + " REGEX ...")
sys.exit(1)
patterns = [re.compile(pat) for pat in args]
def handle(block):
match = False
for line in block:
for pattern in patterns:
if re.search(pattern, line):
match = True
break
if match:
break
if match:
try:
for line in block:
sys.stdout.write(line)
except IOError:
sys.exit(0)
def main():
sep = "^\s*------------------------------------------------------------$"
sep = re.compile(sep)
stdin = sys.stdin
block = []
while True:
line = stdin.readline()
if not line:
if block:
handle(block)
break
if re.match(sep, line):
if not block:
block.append(line)
else:
handle(block)
block = [ line ]
else:
block.append(line)
main()
If you call this program bzr-greplog, you can then do:
bzr log -n0 | bzr-greplog 'branch nick: foo'
to search for branches with the nick foo. Note that the pattern will match anywhere within a line, so it will match a nick of foobar also, for example, or a commit message that happens to have this pattern. In order to avoid (most) such false positives, use an anchored regex instead, e.g. '^\s*branch nick: foo$' (the \s* is necessary because indented commits may begin with spaces). You can also use a script that allows you to search specifically for a branch nick:
#!/bin/sh
bzr log -n0 | bzr-greplog '^\s*branch nick: '"$1"'$'
Known bug: If a commit message contains exactly a bzr log record separator (with the exact same number of dashes), then bzr-greplog will misinterpret the commit as two commits and may leave out the part following the separator.

Sed add text after match

I have a xmltv file that has the following style lines for program start/stop times
<programme start="20150914003000" stop="20150914020000" channel="Noor TV">
I want to add +0000 to the end of the start/stop time like the following
<programme start="20150914003000 +0000" stop="20150914020000 +0000" channel="Noor TV">
I am using windows sed and got this far
sed -r "/<programme start=\"/ s/^([0-9]{14})/\1 +0000/g" < "xml.xml" > "xml2.xml"
its giving me sed cant read >: invalid argument
in the dos windows I can see its adding the +0000 but not writing the new file
I know its something dumb but I just cant figure it out.
thks.
Try this
sed -r "/<programme start=/ s/^([0-9]{14})/\1 +0000/g" "xml.xml" > "xml2.xml"
or (posix version)
sed "/<programme start=/ s/^([0-9]\{14\})/\1 +0000/g" "xml.xml" > "xml2.xml"
$cat xml.xml
<programme start="20150914003000" stop="20150914020000" channel="Noor TV">
$sed -r 's/start="([0-9]{14})" stop="([0-9]{14})"/start="\1 +0000" stop="\2 +0000"/' xml.xml >xml2.xml
$cat xml2.xml
<programme start="20150914003000 +0000" stop="20150914020000 +0000" channel="Noor TV">
had tried it by online linux
The first < needs a backslash, not a forward slash.
sed -r "\<programme start=\"/ s/^([0-9]{14})/\1 +0000/g" < "xml.xml" > "xml2.xml"

Multiple sed substitutions - what's wrong

The idea is to apply both these substitutions to the pattern space
sed -re 's/\v\s+/\t/g' -re 's/[(]([^()]+)[)]\s*\t/\1\t/' movies.list
gives me what I think is a syntax error.
Here is some test data (although it won't match the first pattern.
& The Oriental Groove, Yacine "Els matins a TV3" (2004)
& Vinícius, João Bosco Show da Virada (2011) Teleton 2009 (2009) Teleton 2012 (2012) "Eliana" (2009)
'77 Big Smoker Pig "Pop ràpid" (2011)
'Ariffin, Syaiful Desire (2014/III)
'Aruhane Shaping Bamboo (1979)
'Atu'ake, Taipaleti When the Man Went South (2014)
Just use a ; between your substitution commands:
sed -re 's/\v\s+/\t/g; s/[(]([^()]+)\s*\t/\1\t/' movies.list
The second -r flag is causing the problem. At that point in the argument processing you can't be using that flag apparently. Just drop it.
sed -re 's/\v\s+/\t/g' -e 's/[(]([^()]+)[)]\s*\t/\1\t/' movies.list

print first column and print everything after % sign

I want to print the first column in this case the host IP and everything after % character.
10.162.254.12 3558: 003557: Mar 4 2013 12:13:28: %LINEPROTO-SP-5-UPDOWN: Line protocol on Interface
GigabitEthernet8/37, changed state to up
192.50.0.14 : 2013 Mar 4 13:14:20 EST: %ETHPORT-5-IF_DOWN_LINK_FAILURE: Interface Ethernet17/33 is down (Link
failure)
You have two % characters and didn't specify if everything after the first or last should be printed? Here is both ways using sed:
# First field and everything after first %
$ sed 's/ [^%]*%/ /' file
10.162.254.12 LINEPROTO-SP-5-UPDOWN: Line protocol on Interface GigabitEthernet8/37, changed state to up 192.50.0.14 : 2013 Mar 4 13:14:20 EST: %ETHPORT-5-IF_DOWN_LINK_FAILURE: Interface Ethernet17/33 is down (Link failure)
# First field and everything after last %
$ sed 's/ .*%/ /' file
10.162.254.12 ETHPORT-5-IF_DOWN_LINK_FAILURE: Interface Ethernet17/33 is down (Link failure)
sed 's/\([^ ]*\)[^%]*%/\1 /' input