Use
for i in `awk '/}/ {if (NR!=1) print "";next} \
{printf "%s ",$0,"}"}END{print ""}' yt.txt \
|awk '{print $1}'|sort|uniq \
`; \
do \
awk '/}/ {if (NR!=1) print "";next} \
{printf "%s ",$0,"}"}END{printf ""} \
' yt.txt \
|grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq \
|awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}' \
;done \
Same command in 1 line below (for copying purpose)
for i in `awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{print ""}' yt.txt|awk '{print $1}'|sort|uniq` ; do awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{printf ""}' yt.txt|grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq|awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}' ;done
Explanation:
The for
part will return you the unique heading of the block (abcd/efgh/a.jar
,lkmn/opqr/b.zip
) and pass it to do
block. The do
part will first grep
all the rows for each heading, which would include duplicates also. Then it will exclude the heading and merge all the remaining rows under that heading block, then add the heading at first row. And hardcode }
at the end.
Example
bash-4.2$ cat yt.txt
abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
abcd/efgh/a.jar
{
cdef/ghij/b.class
d.class
}
bash-4.2$ for i in `awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"} \
> END{print ""}' yt.txt |awk '{print $1}'|sort|uniq` \
> ; do awk '/}/ {if (NR!=1) print "";next} {printf "%s ",$0,"}"}END{printf ""}' yt.txt \
> |grep "$i"|sed 's/ /\n/g'|grep -v "$i"|sort|uniq \
> |awk -v var="$i" ' NR==1 {printf var} {print $0} END {print "}"}'\
> ;done
abcd/efgh/a.jar
{
abcd/efgh/a.class
cdef/ghij/b.class
d.class
klmn/opqr/c.class
}
lkmn/opqr/b.zip
{
abcd/efgh/a.class
cdef/ghij/b.class
}
a.jar
block containsd.class
? Add it to the first block or leave it as a block of it's own?