1

I have some text as below:

path => ["/home/Desktop/**/auditd.log",
        "/home/Desktop/**/rsyslog*.log",
        "/home/Desktop/**/snmpd.log",
        "/home/Desktop/**/kernel.log",
        "/home//Desktop/**/ntpd.log",
        "/home/Desktop/**/mysql*.log",
        "/home/Desktop/**/sshd.log",
        "/hme/Desktop/**/su.log",
        "/home/Desktop/**/run-parts(.log"
    ] 

I want to extract the values inside [ ], so I am doing:

sed -n 's/.*\[\(.*\)\]/\1/p'

Sed is not returning anything.

If I do sed -n 's/.*\[\(.*\)log/\1/p it's returning properly the string between [ and log.

"/home/Desktop/**/auditd.",

So it's able to search within the line.

How to make this work??

EDIT:

I created a file with content:

path => [asd,masd,dasd
sdalsd,ad
asdlmas;ldasd
]

When I do grep -o '\[.*\]' it does not work but grep -o '\[.*' this returns the 1st line [asd,masd,dasd. So it's working for single line not for multiple lines.

Siddharth Trikha
  • 2,648
  • 8
  • 57
  • 101
  • sed is line-oriented. Your first pattern doesn't match on any of the lines in your input. – Etan Reisner Dec 16 '14 at 13:46
  • So how to extract multiple lines if one has to ?? Grep also returns searches on same line – Siddharth Trikha Dec 16 '14 at 13:47
  • If you need to match contents between lines use something like `awk` or some tool that can actually understand the input format. The last bit of [this question](http://stackoverflow.com/questions/23934486/is-a-start-end-range-expression-ever-useful-in-awk) shows you a very handy awk pattern for range-of-line processing. – Etan Reisner Dec 16 '14 at 13:48
  • I did use awk: `awk '/\[/,/\]/'` but it's returning an output which is same as input as it's including `path =>` in the output – Siddharth Trikha Dec 16 '14 at 13:50
  • This file is the output of what ? Seems a Data Structure – Gilles Quénot Dec 16 '14 at 13:54
  • It's the output of an `awk` which I did on my file and now I was applying `sed` on the output of awk. Something like this: `awk '/path => \[/,/\]/' abc.conf|sed -n 's/.*\[\(.*\)\]/\1/p'` – Siddharth Trikha Dec 16 '14 at 13:58
  • Yes, a simple range pattern isn't enough you need to then actually transform the lines the way you want. Same as for sed/grep. And as the linked question indicated a range pattern is generally not what you want, the last bit is. – Etan Reisner Dec 16 '14 at 15:10

4 Answers4

1

Try doing this :

$ grep -o '".*",?' file

OUTPUT:

"/home/Desktop/**/auditd.log",
"/home/Desktop/**/rsyslog*.log",
"/home/Desktop/**/snmpd.log",
"/home/Desktop/**/kernel.log",
"/home//Desktop/**/ntpd.log",
"/home/Desktop/**/mysql*.log",
"/home/Desktop/**/sshd.log",
"/hme/Desktop/**/su.log",
"/home/Desktop/**/run-parts(.log"
  • -o for grep print only the matching part
  • " is a literal double quote
  • .* is anything
  • " si the closing double quote
  • , is a literal double quote
  • ? mean o or 1 occurrence
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • Can you please explain this? – Siddharth Trikha Dec 16 '14 at 14:07
  • Ok. I got it, it's capturing only `""` `,` . But in some other case when the input is different, how to capture multiple lines ?? – Siddharth Trikha Dec 16 '14 at 14:11
  • it's capturing not only "" but also what's inside. Next time, you have to adapt the regex. – Gilles Quénot Dec 16 '14 at 14:20
  • I meant what if no particular pattern is there in the input. Like in the above case ".*,?" was a pattern and we greped that. What if we had to capture text b/w [ ] but data inside [ ] was random. In that case doing a .* does not work for multiple lines. So how to achieve that? – Siddharth Trikha Dec 16 '14 at 15:09
  • I created a file with content: `path => [asd,masd,dasd sdalsd,ad asdlmas;ldasd ] ` When I do `grep -o '\[.*\]'` it does not work but `grep -o '\[.*'` this returns the 1st line `[asd,masd,dasd`. So it's working for single line not for multiple lines. – Siddharth Trikha Dec 16 '14 at 15:34
  • I edited my question plz check there. In comments the file input formatting could not be done properly. – Siddharth Trikha Dec 16 '14 at 15:37
  • grep is line oriented. – Gilles Quénot Dec 16 '14 at 15:39
  • Yes. So can we achieve to extract multiple lines. I know sed is line oriented too and awk returns an output with whole line like path => will also be there. So is there a way? – Siddharth Trikha Dec 16 '14 at 15:43
  • In your answer there must be a `\?` rather than just `?`, something like this: `grep -o '".*",\?' file`. – Siddharth Trikha Dec 17 '14 at 08:26
1

Well, I was a bit too slow, but I think the question of how to apply sed substitutions to a whole file as a block rather than on a line-by-line basis merits a general answer, so I'll leave one here.

In your specific case, you could use this pattern:

sed -n 'H; $ { x; s/.*\[\(.*\)\].*/\1/; p; }' foo.txt

The general trick is

sed -n 'H; $ { x; s/pattern/replacement/flags; p; }' file

What this means is: Every line that comes in is appended to the hold buffer (with the H command), and at the end of the file ($), when the whole file is in the hold buffer, the stuff between the brackets is executed. In that block, the hold buffer is swapped with the pattern space (x), then the substitution is done, and what remains in the pattern space is printed (p).

EDIT: One caveat of this simple form is that it doesn't work properly if your pattern wants to match the beginning of the file; for reasons the hold buffer is not entirely empty when sed is first called (it contains an empty line). If this is important, the slightly more complicated form

sed -n '1 h; 1 !H; $ { x; s/pattern/replacement/flags; p; }' file

fixes it. This will use h instead of H for the first line, which overwrites the hold buffer with the pattern space rather than appending the pattern space to the hold buffer.

Wintermute
  • 42,983
  • 5
  • 77
  • 80
  • `s/.*\[` could failed because the first `.*` take the loingest possible pattern, so it take until last `[` before the last `]` that could be in the middle of the block. I propose to use `^[^[]*\[` instead – NeronLeVelu Dec 16 '14 at 15:14
  • 1
    Depending on what exactly OP wants to match if there are several pairs of brackets in the file, that is a valid point, yes. I only copied OP's regex. – Wintermute Dec 16 '14 at 15:42
  • This is the `"/home/Desktop/**/run-parts(.log"` line that make me write the remark suspecting other special char like `[` possible in string – NeronLeVelu Dec 17 '14 at 06:40
0

You can do it with awk by replacing .*[ or ] or white spaces with nothing:

$ awk '{gsub(/.*\[|\]| /, ""); print}' filename

"/home/Desktop/**/auditd.log",
"/home/Desktop/**/rsyslog*.log",
"/home/Desktop/**/snmpd.log",
"/home/Desktop/**/kernel.log",
"/home//Desktop/**/ntpd.log",
"/home/Desktop/**/mysql*.log",
"/home/Desktop/**/sshd.log",
"/hme/Desktop/**/su.log",
"/home/Desktop/**/run-parts(.log"
jherran
  • 3,337
  • 8
  • 37
  • 54
0

from your sample, it could also be (treat only first and last line)

sed '1s/^[^[]*\[//;$d' YourFile
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43