1

I have the folowing file which is called test.html:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<meta name="generator" content="SQL*Plus 12.2.0">
<style type='text/css'> body {font:10pt Arial,Helvetica,sans-serif; color:black; background:White;} p {font:10pt Arial,Helvetica,sans-serif; color:black; background:White;} table,tr,td {font:10pt Arial,Helvetica,sans-serif; color:Black; background:#f7f7e7; padding:0px 0px 0px 0px; margin:0px 0px 0px 0px;} th {font:bold 10pt Arial,Helvetica,sans-serif; color:#336699; background:#cccc99; padding:0px 0px 0px 0px;} h1 {font:16pt Arial,Helvetica,Geneva,sans-serif; color:#336699; background-color:White; border-bottom:1px solid #cccc99; margin-top:0pt; margin-bottom:0pt; padding:0px 0px 0px 0px;-
} h2 {font:bold 10pt Arial,Helvetica,Geneva,sans-serif; color:#336699; background-color:White; margin-top:4pt; margin-bottom:0pt;} a {font:9pt Arial,Helvetica,sans-serif; color:#663300; background:#ffffff; margin-top:0pt; margin-bottom:0pt; vertical-align:top;}</style><title>SQL*Plus Report</title>
</head>
<body>
<p>
<table border='1' width='90%' align='center' summary='Script output'>
<tr>
<th scope="col">
NAME
</th>
<th scope="col">
FREE_PERCENT
</th>
</tr>
<tr>
<td>
DG_BACKUP
</td>
<td>
50%
</td>
</tr>
<tr>
<td>
DG_DATA
</td>
<td>
96%
</td>
</tr>
<tr>
<td>
DG_INDEX
</td>
<td>
80%
</td>
</tr>
<tr>
<td>
DG_ORA
</td>
<td>
19%
</td>
</tr>
</table>
<p>
<br>
</body>
</html>

I want to find the values that are less than 20% and set the background to red:

<td bgcolor="red">

using sed or any other tool.  So, for example,

<td>
80%
</td>

would remain unchanged, but

<td>
19%
</td>

wound be changed to

<td bgcolor="red">
19%
</td>

Script I have tried so far.

number_of_lines_test=(`grep -n % test.html |sed -e '1d' |awk -F"[:%]" '{if ($2 <= 50) print $1}'`)
for i in `seq 0 $((${#number_of_lines_test[@]} - 1))`
do
sed -i -e "$((${number_of_lines_test[i]} - 1))s/<td>/<td bgcolor=\"red\">/" test.html
done
  • welcome to U&L, we are not a free scrpting service, what have you tried so far ? – Archemar Jun 25 '18 at 11:10
  • actually i am new to scripting and i have thought of using sed the problem is after looping over the lines and check the value after using awk to cut the % sympol but how can i edit line before the matching reasults – ammar Jun 25 '18 at 11:23
  • This would be a better question if you clarified what might happen and what won’t.  For example, I’m guessing that, as illustrated, you always have the data on a separate line, and never have <td>19%</td> all on one line.  Is the number always the first thing on the line?  Is the number always followed by %?  Is the number always followed by % and nothing else?  Can the number be less than 10?  If so, does it have a leading zero?  (E.g., can we have 7% or 07%?  For that matter, how about007% or 017%?)  … (Cont’d) – G-Man Aug 16 '18 at 3:01
  • (Cont’d) …  Can there be a decimal point (e.g., 17.5%)?  Can the value be negative?  Will there ever be a line that looks like a value that needs to be colored, but isn’t (e.g., can you have 19% in the NAME column)?  Is the <td> always on a separate line, all by itself?   Please do not respond in comments; edit your question to make it clearer and more complete. – G-Man Aug 16 '18 at 3:01
0

Try this,

number=(`grep -n "^[0-1][0-9]" test.html | awk -F ':' '{a=$1-1;print a}'`)
for i in ${number[@]} 
do
  sed -i "$i s/.*/<td bgcolor=\"red\">/" test.html
done
0

I presume you understand that your solution, and SivaPrasath’s answer, run sed once for every data line that needs to be changed (in addition to running grep and awk once, and, in your code, an extra sed).

  • awk and sed are very powerful commands.  You hardly ever to use them together, or together with grep.
  • awk knows about line numbers.  If you find yourself using grep -n to generate line numbers, and then processing them with awk, you’re probably making more work for yourself than you need to.
  • Running commands takes time.  If your file is 100 lines long, you probably won’t notice the amount of time SivaPrasath’s answer takes.  If your file is a million lines long, SivaPrasath’s answer will run sed approximately 125,000 times.  That will probably be noticeable, and is unnecessary.

If the “value” will always be of the form NN%, where NN is a two-digit decimal integer between 00 and 19, you can do everything with this one sed command:

sed '/<td>/ { N; s/\(<td\)\(>\n[01][0-9]%\)/\1 bgcolor="red"\2/; }' test.html

When it sees a line that contains <td>, it executes the commands in the {} braces.  N reads the next line from the file (the one that contains the value) and appends it to the pattern space.  Then it does an s (substitute) that replaces <td> with <td bgcolor="red"> if the (percentage) value matches [01][0-9] (i.e., 00 through 19).

If the value can be a single digit (i.e., 0 through 9 rather than 00 through 09), then use

sed '/<td>/ { N; s/\(<td\)\(>\n[0-9]%\)/\1 bgcolor="red"\2/; s/\(<td\)\(>\n[01][0-9]%\)/\1 bgcolor="red"\2/; }'

which is the same logic, but with one s command to handle single-digit values and one to handle double-digit values.  Or, if you have GNU sed (standard on Linux systems), you can do

sed -r '/<td>/ { N; s/(<td)(>\n[01]?[0-9]%)/\1 bgcolor="red"\2/; }' test.html

which uses the extended regular expression [01]?[0-9] to match either a single-digit value or a two-digit value less than 20.

sed can handle non-integers (e.g., 17.5%), values with more than two digits (with leading zeroes) and negative numbers.  If you edit your question to indicate what forms you need to process, I’ll update this section.


awk programs, while a bit more verbose, are much more powerful, as they can easily remember information from one line to another.  So the below script recognizes a broad variety of numeric forms:

awk -F% '
        last_was_td {
                  if ($1 < 20) print "<td bgcolor=\"red\">"
                  else print "<td>"
                }
                { last_was_td = 0 }
        /<td>/  {
                  last_was_td = 1
                  next
                }
                { print }
        ' test.html

Start reading in the middle.  If a line contains <td>, the program sets the last_was_td flag and skips to the next input line.  Otherwise the flag is cleared and the line is printed.  Now reading the script from the top: if the previous line was a <td>, and the number (the first field, as split by the % field separator) is less than 20, we print <td bgcolor="red">; otherwise we print <td>.  (The value itself gets printed by the general print statement at the end.)


All of the above answers write the revised file to the standard output.  As you know, you can modify the file in place with sed -i.  With awk, write the output to a temporary file and copy it back over the input file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.