In awk
(note that this one will print any empty lines that come before the first non-empty one):
$ awk '{ if(! NF){$0=last}else{last=$0;}}1' file
101 abc group1
765 efg group2
345 hij group4
345 hij group4
456 gfd group9
762 ert group7
762 ert group7
762 ert group7
554 fgt group11
Explanation:
NF
holds the number of fields. If the line is empty, there are no fields so the variable will be 0
.
if(! NF){$0=last}
: if the number of fields is 0 (empty line), set the current line ($0
) to the value of the variable last
.
else{last=$0;}
: if there are fields, so this line is not empty, set last
to hold the contents of this line.
1
: the lone one at the end is an awk trick: when something evaluates to true (1 or any other integer greater than 0 is always true, since 0 is false) awk will print the current line. So that 1
is equivalent to print $0
.
$ awk '! NF ? $0=last : last=$0;' file
101 abc group1
765 efg group2
345 hij group4
345 hij group4
456 gfd group9
762 ert group7
762 ert group7
762 ert group7
554 fgt group11
Explanation
This is the same idea as above, but written in a more concise way. We are using the ternary operator. Since one of the two conditions will always be true (either NF
is true or it is not true, so the ternary operator will always return true), both outcomes result in the line being printed (except for cases where the line is empty and no non-empty lines have been seen or if a line consistes of nothing but 0
). However, if NF
is not set, we set $0
to last
and if it is set, we set last
to $0
. The result is the output we want.
Since the above will not print lines that are just 0
, you can use this instead of that is a problem for you:
awk '{! NF ? $0=last : last=$0};1' file
perl -lpe '$_ ||= $last; $last = $_'
works. By the way your expected output has "group3" in two lines, but there was no "group3" in the input. – Dec 12 '20 at 14:30