0

I'm trying to export a css rule from a css file with awk but I am not able to do it. I need only the rules containing the "background-image" line.

#rule{
...
background-image: url(path);
}

Here's what I have tried so far:

awk '/^[#].*{.*background-image.*/','/}/' css/file.css

What am I doing wrong?

At this moment I got the best result using:

/^[#A-Za-z.]/ { accum = 1; }
accum == 1 { css = css $0 "\n"; }
accum == 1 && /background-image/ { found = 1; }
/\}/ { accum = 0; if (found == 1) print css; found = 0; css = ""; }

and it allows me to get a full block with all the selectors

user1638466
  • 300
  • 1
  • 5
  • 18
  • What is your expected output? – anubhava Feb 16 '15 at 14:15
  • Do you mean "*export* CSS rule"? – Richard Feb 16 '15 at 14:16
  • yes "export". I have many #rules (also .rules), I want to export only the ones containing "background-image: ... " – user1638466 Feb 16 '15 at 14:18
  • It has been a long time (two decades... ) but I seem to recall that awk matches just one line at a time. But it appears that you can do multi-line matches with contemporary awk implementations: http://stackoverflow.com/a/12390518/67392 – Richard Feb 16 '15 at 14:24
  • mmm so awk is not capable – user1638466 Feb 16 '15 at 14:48
  • As far as CSS goes, you're making assumptions with `#`. Is there a reason you can't just search for `/background-image/`? – shawnt00 Feb 16 '15 at 14:55
  • I need the full block from # (or . ) to } – user1638466 Feb 16 '15 at 14:58
  • If your awk supports multi-line searches then you probably messed up at the end starting with the comma `,'/}/'` You might need to escape the braces as well. – shawnt00 Feb 16 '15 at 15:10
  • @RIchard is wrong, awk has always been record-based, not line-based, hence the `RS` variable. – Ed Morton Feb 16 '15 at 15:52
  • @user1638466 you cannot include the script delimiter character (`'`) inside a script since it DOES delimit the script and `#` is already just a literal char inside a regexp so the syntax for what you were trying to do would be `'/^#.*{.*background-image/,/}/'`. Never use ranges `/start/,/end/` though as they make trivial scripts very slightly briefer but then even the tiniest change in requirements requires duplication of conditions or a complete rewrite. Always use a flag like `/start/{f=1} f; /end/{f=0}` instead. – Ed Morton Feb 16 '15 at 15:55

1 Answers1

1

Turn accumulation on after matching an open brace. Accumulate all lines while flag is on. Turn off after closing brace is seen. Print only if background-image found during accumulation. If you want to include lines before the match you do do something like this.

{ line4 = line3; line3 = line2; line2 = line1; line1 = $0 "\n"; }
/\{/ { accum = 1; head = line4 line3 line2 line1; }
accum == 1 { css = css $0 "\n"; }
accum == 1 && /background-image/ { found = 1; }
/\}/ {
    accum = 0;
    if (found == 1) print head css;
    found = 0; css = "";
}

You had said in comments "I need the full block from # (or . ) to }" but I'm getting the impression that you really just want this.

/\{/ { selector = $0 }
/background-image/ { print selector "\n" $0 "\n}\n" }
shawnt00
  • 16,443
  • 3
  • 17
  • 22
  • What is this syntax about? – user1638466 Feb 16 '15 at 15:04
  • It's like a C program. A generic awk script has patterns (often a regular expression) and actions (inside braces). You probably want to put this in it's own file and refer to it from the command line. – shawnt00 Feb 16 '15 at 15:13
  • I have a syntax error near } in the first line. I m doing awk [that stuff] file.cs – user1638466 Feb 16 '15 at 15:15
  • Try putting the script in a file, like say cssbckimg.awk, and use `awk -f cssbckimg.awk mycss.css` from the command line. – shawnt00 Feb 16 '15 at 15:23
  • same issue, syntax error in the second line near \n – user1638466 Feb 16 '15 at 15:25
  • Maybe it was the single quotes. I just made an edit. – shawnt00 Feb 16 '15 at 15:27
  • +1 but no need to escape `{` and `}` and no need for the trailing semicolons, and no value to specifying the same condition (`accum == 1`) twice and per the question it looks like your first RE should be `/^#.*{/`. – Ed Morton Feb 16 '15 at 16:01
  • @Ed I realized all those thing but I figured this was safer and easier to understand. There are so many implementations out there and I haven't written many awk scripts in the last 15 years either. – shawnt00 Feb 16 '15 at 16:11
  • @Ed I dropped the `#` character because I'm just generically matching all css rules regardless of the selector. I figured that OP could tweak that after it started producing output and it was determined that the more precise match was important. – shawnt00 Feb 16 '15 at 16:15
  • I see that it works, but, if I have a rule written like: #rule1, #rule2 { background-image.... } I get only: { background-image.... } – user1638466 Feb 16 '15 at 16:30
  • If the opening brace is on the same line as the selector I don't think there's a problem. I guess you could match on `#` instead or add a variety of conditions for setting `accum = 1` if the formatting isn't consistent. – shawnt00 Feb 16 '15 at 16:40
  • Well using # it's ok, but what if I want "# or ." ? The dot is a special char – user1638466 Feb 16 '15 at 16:46
  • You should check the reference for regular expression syntax. When you need to match a literal special character put a `\` in front of it though. – shawnt00 Feb 16 '15 at 16:52
  • It's ok really thanks. Is there a way to ignore the rows that doesn't contain "background-image" without losing selectors and brackets? – user1638466 Feb 16 '15 at 16:56
  • @user1638466 please edit your question to provide a few (e.g. 5 or 6) blocks of REPRESENTATIVE input and associated output that covers all of the variations you might have. Doling them out piece-wise in comments is not useful. – Ed Morton Feb 16 '15 at 16:57
  • @Ed I added what is the current state of the work saying what it allows to do. – user1638466 Feb 16 '15 at 17:57
  • @shawnt00 I see you are very expert with regex! And I really need to thank you for the syntax that you gave me. You are right, I asked for the entire block but I m just curious about how to edit the expression in order to get ONLY the background-image row (if it is possible). I tried /\{/ { selector = $0 } /background-image/ { print selector "\n" $0 "\n}\n" } but I lost all the selectors because it starts from { – user1638466 Feb 16 '15 at 18:01
  • Then the `{` must be on it's own line after the selectors. Use a different expression to match the start. I'm thinking `/^[.#]/` but I wonder about whitespace characters causing problems. – shawnt00 Feb 16 '15 at 18:12
  • @user1638466 yes you did but you did not provide the information I asked for and which would enable us to help you solve your problem. Without it we're just guessing. – Ed Morton Feb 16 '15 at 21:34