I’m getting totally lost in shell programming, mainly because every site I use offers different tool to do pattern matching. So my question is what tool to use to do simple pattern matching in piped stream.
Context: I have named.conf file, and I need all zones names in a simple file for further processing. So I do ~$ cat named.local | grep zone and get totally lost here. My output is ~hundred or so newlines in form ‘zone "domain.tld" {‘ and I need text in double quotes.
I think what you’re looking for is
sed… it’s a stream editor which will let you do replacements on a line-by-line basis.As you’re explaining it, the command `cat named.local | grep zone’ gives you an output a little like this:
I’m guessing you want the output to be something like this, since you said you need the text in double quotes:
So, in reality, from each line we just want the text between the double-quotes (including the double-quotes themselves.)
I’m not sure you’re familiar with Regular Expressions, but they are an invaluable tool for any person writing shell scripts. For example, the regular expression
/.o.e/would match any line where there’s a word with the 2nd letter was a lower-caseo, and the 4th wase. This would match string containing words like ‘zone‘, ‘tone‘, or even ‘I am tone-deaf.‘The trick there was to use the
.(dot) character to mean ‘any letter’. There’s a couple of other special characters, such as*which means ‘repeat the previous character 0 or more times’. Thus a regular expression likea*would match ‘a‘, ‘aaaaaaa‘, or an empty string: ”So you can match the string inside the quotes using:
/'.*'/There’s another thing you would know about
sed(and by the comments, you already do!) – it allows backtracking. Once you’ve told it how to recognize a word, you can have it use that word as part of the replacement. For example, let’s say that you wanted to turn this list:Into this list:
First, you’d look for the string inside the quotes. We already saw that, it was
/'.*'/.Next, we want to use what’s inside the quotes. We can group it using parens:
/'(.*)'/If we wanted to replace the text with the quotes with an underscore, we’d do a replace:
s/'(.*)'/_/, and that would leave us with:But we have backtracking! That’ll let us recall what was inside the parens, using the symbol
\1. So if we do now:s/'(.*)'/\1/we’ll get:Because the quotes weren’t in the parens, they weren’t part of the contents of
\1!To only leave the stuff inside the double-quotes, we need to match the entire line. To do that we have
^(which means ‘beginning of line’), and$(which means ‘end of line’.)So now if we use
s/^.*'(.*)'.*$/\1/, we’ll get:Why? Let’s read the regular expression
s/^.*'(.*)'.*$/\1/from left-to-right:s/– Start a substitution regular expression^– Look for the beginning of the line. Start from there..*– Keep going, reading every character, until…'– … until you reach a double-quote.(– start a group a characters we might want to recall later when backtracking..*– Keep going, reading every character, until…)– (pssst! close the group!)'– … until you reach a double-quote..*– Keep going, reading every character, until…$– The end of the line!/– use what’s after this to replace what you matched\1– paste the contents of the first group (what was in the parens) matched./– end of regular expressionIn plain English: ‘Read the entire line, copying aside the text between the double-quotes. Then replace the entire line with the content between the double qoutes.’
You can even add double-quote around the replacing text
s/^.*'(.*)'.*$/'\1'/, so we’ll get:And that can be used by
sedto replace the line with the content from within the quotes:(This is just shell-escaped to deal with the double-quotes and slashes and stuff.)
So the whole command would be something like: