AWK replace null column with the previous row column value

Viewed 298

I have a series of field-delimited files (symbol | ) with varying column widths:

File 1:

2p              | 2P*    |  1/2 |    2 |                 10.19880615024                       |
2s              | 2S     |  1/2 |    2 |                 10.19881052514816                    |
2               |        |      |    8 |                 10.1988358                           |
2p              | 2P*    |  3/2 |    4 |                 10.19885151459                       |
3p              | 2P*    |  1/2 |    2 |                 12.0874936591                        |
3s              | 2S     |  1/2 |    2 |                 12.0874949611                        |
3               |        |      |   18 |                 12.0875052                           |
3d              | 2D     |  3/2 |    4 |                 12.0875070783                        |

File 2:

2s2.2p3            | 4S*    |  3/2 |    4 |             0.0000000               |
2s2.2p3            | 2D*    |  5/2 |    6 |             2.3835298               |
2s2.2p3            |        |  3/2 |    4 |             2.3846100               |
2s2.2p3            | 2P*    |  1/2 |    2 |             3.5755704               |
2s2.2p3            |        |  3/2 |    4 |             3.5756182               |
2s2.2p2.(3P).3s    | 4P     |  1/2 |    2 |            10.3259087               |
2s2.2p2.(3P).3s    |        |  3/2 |    4 |            10.3300944               |
2s2.2p2.(3P).3s    |        |  5/2 |    6 |            10.3358956               |
2s2.2p2.(3P).3s    | 2P     |  1/2 |    2 |            10.6796703               |
2s2.2p2.(3P).3s    |        |  3/2 |    4 |            10.6899808               |

and I would like to fill the blanks in the second column with the corresponding values in the last non-NULL column above: Example for file 2:

2s2.2p3            | 4S*    |  3/2 |    4 |             0.0000000               |
2s2.2p3            | 2D*    |  5/2 |    6 |             2.3835298               |
2s2.2p3            | 2D*    |  3/2 |    4 |             2.3846100               |
2s2.2p3            | 2P*    |  1/2 |    2 |             3.5755704               |
2s2.2p3            | 2P*    |  3/2 |    4 |             3.5756182               |
2s2.2p2.(3P).3s    | 4P     |  1/2 |    2 |            10.3259087               |
2s2.2p2.(3P).3s    | 4P     |  3/2 |    4 |            10.3300944               |
2s2.2p2.(3P).3s    | 4P     |  5/2 |    6 |            10.3358956               |
2s2.2p2.(3P).3s    | 2P     |  1/2 |    2 |            10.6796703               |
2s2.2p2.(3P).3s    | 2P     |  3/2 |    4 |            10.6899808               |

This question is similar to the one in here where I can do this in the first column using awk through the command:

awk -F"|" '/^ /{$0=(x)substr($0,length(x)+1)}{x=$1}1' "$file"

however I am not knowleadgeable enough to make it work in the second column (or any arbitrary colum for that matter).

Can someone help? Thanks in advance!

3 Answers

Using your file2 as an example, you may use this awk command:

awk -v c=2 'BEGIN {FS=OFS="|"} $c ~ /^[ \t]*$/ {$c = p} {p = $c} 1' file

2s2.2p3            | 4S*    |  3/2 |    4 |             0.0000000               |
2s2.2p3            | 2D*    |  5/2 |    6 |             2.3835298               |
2s2.2p3            | 2D*    |  3/2 |    4 |             2.3846100               |
2s2.2p3            | 2P*    |  1/2 |    2 |             3.5755704               |
2s2.2p3            | 2P*    |  3/2 |    4 |             3.5756182               |
2s2.2p2.(3P).3s    | 4P     |  1/2 |    2 |            10.3259087               |
2s2.2p2.(3P).3s    | 4P     |  3/2 |    4 |            10.3300944               |
2s2.2p2.(3P).3s    | 4P     |  5/2 |    6 |            10.3358956               |
2s2.2p2.(3P).3s    | 2P     |  1/2 |    2 |            10.6796703               |
2s2.2p2.(3P).3s    | 2P     |  3/2 |    4 |            10.6899808               |

To populate 3rd column just pass c=3 in place of c=2.

Answer to a previous version saying the file was tab separated...

If that column doesn't have values like 0P or 0D*, this might be helpful for you:

awk 'BEGIN{FS=OFS="\t"}!$3{$3=e}{print;e=$3}' file

Explanation:

  • Set field separators to tab only
  • If $3 is empty, set $3 to variable e
  • print line
  • set variable e to $3 for next record

This will take care of all fields iin the file

awk '
    BEGIN {FS = OFS = "|"}
    {
        for (i=1; i<=NF; i++)
            if ($i ~ /[^[:blank:]]/) f[i]=$i   # remember the value of this field
            else $i = f[i]                     # use the previous field value
        print
    }
' file ...

This of course can't do anything about empty fields in the first line of the file.

If you use GNU awk, you can write the results back to the file:

gawk -i inplace '...' file ...
Related