6

I have several CSS files under a folder contains 0.2rem or 0.5rem 0.6rem, now I want them to be all divided by 2, become 0.1rem and 0.25rem, 0.3rem. How can I use awk or sed or gawk to accomplish this?

I tried the following command but have no success:

find . -name "*.css" | xargs gawk -i inplace '{gsub(/([0-9\.]+)rem/, "(\\1 * 0.5)rem"); print $0}'

4 Answers4

8

Not sure about sed/gawk, but here's one with perl

$ echo '0.2rem or 0.5rem 0.6rem' | perl -pe 's/\d+(\.\d+)?(?=rem)/$&*0.5/ge'
0.1rem or 0.25rem 0.3rem
  • \d+(\.\d+)? match digits with optional fractional part
    • (?=rem) to ensure the number is followed by rem
  • $&*0.5 multiply the number by 0.5 - the e modifier allows to use Perl code instead of string in replacement section


Applying to files:

find . -name "*.css" -exec perl -i -pe 's/\d+(\.\d+)?(?=rem)/$&*0.5/ge' {} +

See also: Why is looping over find's output bad practice?

Sundeep
  • 12,008
  • That link is about looping over the output of find (e.g. for i in $(find…)), not using find's internal loop (-exec or -execdir). – Sparhawk Mar 14 '18 at 22:13
  • @Sparhawk but the answers cover that aspect... and has a quote that I like very much... find's business is evaluating expressions -- not locating files. Yes, find certainly locates files; but that's really just a side effect. – Sundeep Mar 15 '18 at 03:13
  • 1
    Ah okay, yes I see mention of that now. I didn't look so deep before. Still, I'm not sure that there's a better solution for your example code. – Sparhawk Mar 15 '18 at 03:17
5

find + GNU awk solution:

find . -type f -name "*.css" -exec gawk -i inplace \
'{ for (i=1; i<=NF; i++) 
       if ($i ~ /^[0-9]+\.[0-9]+rem/) { v=$i/2; sub(/^[0-9]+\.[0-9]+/, "", $i); $i=v $i } 
 }1' {} \;
  • Thank you! I tried with some change: find . -name "*.css" | xargs gawk -i inplace '{ for (i=1; i<=NF; i++) if ($i ~ /[0-9]\.[0-9]rem/) { sub("rem", "", $i); $i = $i * 0.4"rem" } }1', everything works fine, just the ; is striped on every line. For example, padding-bottom: 2rem; becomes padding-bottom: 1rem after change. Do you know why? – Zhang Buzz Mar 14 '18 at 07:28
  • @ZhangBuzz, you did not mention that in your question. Anyway, see my update – RomanPerekhrest Mar 14 '18 at 07:37
  • I got it! The final command I use is as this: find . -name "*.css" | xargs gawk -i inplace '{ for (i=1; i<=NF; i++) if ($i ~ /[0-9]+\.[0-9]+rem/) { v=$i/2; sub(/[0-9]+\.[0-9]+/, "", $i); $i=v $i } }1' – Zhang Buzz Mar 14 '18 at 07:58
4

With gawk, you could use RS that is treated as a regexp there and the fact that there, RT contains what was matched by RS. So:

find . -name '*.css' -type f -exec \
  gawk -i /usr/share/awk/inplace.awk -v RS='[0-9.]*[0-9]rem' -v ORS= 'RT{$0=$0 RT/2 "rem"};1' {} +

Do not use -i inplace as gawk tries to load the inplace extension (as inplace or inplace.awk) from the current working directory first, where someone could have planted malware. The path of the inplace extension supplied with gawk may vary with the system, see the output of gawk 'BEGIN{print ENVIRON["AWKPATH"]}'

1
gawk -i inplace '
{
    for(i = 1; i <= NF; i++) {
        if($i ~ /[0-9]+(\.[0-9]+)?rem/) 
            $i = $i / 2 "rem"            
    }
    print
}' file_*

The 3 files content before the program execution

The tail -n +1 -- file_* command shows the multiple files content at once.

$ tail -n +1 -- file_*

==> file_1 <==
0.2rem lorem ipsum 0.5rem
Lorem 0.2rem ipsum dolor sit amet, 0.5rem consectetur adipiscing elit magna aliqua.
Lorem ipsum 0.8rem dolor sit amet, 6rem consectetur 2rem adipiscing elit magna aliqua.
0.2rem lorem ipsum 0.5rem

==> file_2 <==
0.2rem lorem ipsum 0.5rem
Lorem 0.2rem ipsum dolor sit amet, 0.5rem consectetur adipiscing elit magna aliqua.
0.2rem lorem ipsum 0.5rem
Lorem ipsum 0.8rem dolor sit amet, 6rem consectetur 2rem adipiscing elit magna aliqua.

==> file_3 <==
0.2rem lorem ipsum 0.5rem
Lorem 0.2rem ipsum dolor sit amet, 0.5rem consectetur adipiscing elit magna aliqua.
Lorem ipsum 0.8rem dolor sit amet, 6rem consectetur 2rem adipiscing elit magna aliqua.

The 3 files content after the program execution

$ tail -n +1 -- file_*

==> file_1 <==
0.1rem lorem ipsum 0.25rem
Lorem 0.1rem ipsum dolor sit amet, 0.25rem consectetur adipiscing elit magna aliqua.
Lorem ipsum 0.4rem dolor sit amet, 3rem consectetur 1rem adipiscing elit magna aliqua.
0.1rem lorem ipsum 0.25rem

==> file_2 <==
0.1rem lorem ipsum 0.25rem
Lorem 0.1rem ipsum dolor sit amet, 0.25rem consectetur adipiscing elit magna aliqua.
0.1rem lorem ipsum 0.25rem
Lorem ipsum 0.4rem dolor sit amet, 3rem consectetur 1rem adipiscing elit magna aliqua.

==> file_3 <==
0.1rem lorem ipsum 0.25rem
Lorem 0.1rem ipsum dolor sit amet, 0.25rem consectetur adipiscing elit magna aliqua.
Lorem ipsum 0.4rem dolor sit amet, 3rem consectetur 1rem adipiscing elit magna aliqua.
MiniMax
  • 4,123