Code Comments
Programming Forum and web based access to our favorite programming groups.Ok, need some more help formatting another report. What I'm trying to do is take a file that looks something similar to the following: Name: Fred INFO: 1/text/text/text, 2/text/text/text, etc. Name: Sam INFO: 1/text/text/text, 2/text/text/text, etc. The fields after 'INFO:' could vary from none to quite a number. I'd like to be able to generate a report that would end up looking something like this: Name Info ---- ---- Fred 1/text/text/text 2/text/text/text 3/text/text/text Sam 1/text/text/text 2/text/text/text 3/text/text/text The problem is I haven't quite been able to puzzle through it using awk. If someone has a pointer I'd very much appreciate it. Thanks! -- Link King king@kinger.net
Post Follow-up to this messageIn article <Pine.LNX.4.44.0402101708220.25758-100000@mogul.kinger.net>, Link King <king@kinger.net> wrote: > Ok, need some more help formatting another report. What I'm trying to do > is take a file that looks something similar to the following: > > Name: Fred INFO: 1/text/text/text, 2/text/text/text, etc. > Name: Sam INFO: 1/text/text/text, 2/text/text/text, etc. > > The fields after 'INFO:' could vary from none to quite a number. I'd like > to be able to generate a report that would end up looking something like > this: > > Name Info > ---- ---- > Fred 1/text/text/text > 2/text/text/text > 3/text/text/text > Sam 1/text/text/text > 2/text/text/text > 3/text/text/text > > The problem is I haven't quite been able to puzzle through it using awk. > If someone has a pointer I'd very much appreciate it. Thanks! I would probably change the ':' and ',' to white space and then just print the second and fourth field on one line and the rest on following lines. -- Robert B. Peirce, Venetia, PA 724-941-6883 bob AT peirce-family.com [Mac] rbp AT cooksonpeirce.com [Office]
Post Follow-up to this messageIn article <Pine.LNX.4.44.0402101708220.25758-100000@mogul.kinger.net>,
Link King <king@kinger.net> wrote:
% Name: Fred INFO: 1/text/text/text, 2/text/text/text, etc.
% Name: Sam INFO: 1/text/text/text, 2/text/text/text, etc.
You'll need to either store all the values or make two passes. I suggest
setting
FS = " *(INFO)?: +"
so you'll have
$1 = "Name"
$2 = "Fred"
$3 = "1/text/..."
You can store this in an array, and store the maximum length at the
same time
info[$2] = $3
maxlen = maxlen >= length($2) ? maxlen : length($2)
At the end, you split up the info into another array using split
for (name in info) {
nf = split(info[name], f, /, */)
then print the first piece of information with the name, and the other
pieces of information without the name. You use printf to do the
printing, and specify a width on the first field. If you knew all the
names were going to be less than 10 characters, you could write
printf "%-10s %s\n", "Name", "Info"
printf "%-10s %s\n", "----", "----"
printf "%-10s %s\n", name, f[1]
and so on. You don't know that, but you do know the names will be
less than maxlen characters long, so you can put that into the
format string, either like this:
fmtstring = "%-" maxlen "s %s\n"
printf fmtstring, name, f[1]
or like this
printf "%-*s %s\n", maxlen, name, f[1]
The former is more portable and probably easier to use and faster.
Putting it all together (but not testing it)
BEGIN { FS = " *(INFO)?: +" }
END {
fmtstring = "%-" maxlen "s %s\n"
printf fmtstring, "Name", "Info"
printf fmtstring, "----", "----"
for (name in info) {
nf = split(info[name], f, /, */)
printf fmtstring, name, f[1]
for (i = 2; i <= nf; i++)
printf fmtstring, "", f[i]
}
}
{ info[$2] = $3
l = length($2)
if (maxlen < l)
maxlen = l
}
--
Patrick TJ McPhee
East York Canada
ptjm@interlog.com
Post Follow-up to this message
Patrick,
Thanks for the reply. It's very helpful. However, I think I've
oversimplified things a bit and I'm only partially successful in getting
things to format properly. Here is an actual record from the file I'm
working with:
Host: 10.10.10.10 (xyz.abc.com) Ports: 53/open/tcp//domain?///, 53/ope
n/udp//domain?///, 25/open/tcp//smtp///
There will be a large number of records similar to this. What I'd like to
see is something like this per record:
Host Ports
---- -----
10.10.10.10 (xyz.abc.com) 53/open/tcp//domain
53/open/udp//domain
25/open/tcp//smtp
I'm close with the pointers you've given but not quite there. Two things
in particular. One, the hosts/records are not printing out in the order
they appear in the file. Second, the formatting for the first line is
off. So, instead of the above it will appear like so:
Host Ports
---- -----
10.10.10.10 (xyz.abc.com) 53/open/tcp//domain
53/open/udp//domain
25/open/tcp//smtp
Or something like that. Have tried a number of different formatting
options to no avail thus far. Any additional pointers would be great.
Thanks!
-Link
> In article <Pine.LNX.4.44.0402101708220.25758-100000@mogul.kinger.net>,
> Link King <king@kinger.net> wrote:
>
> % Name: Fred INFO: 1/text/text/text, 2/text/text/text, etc.
> % Name: Sam INFO: 1/text/text/text, 2/text/text/text, etc.
>
> You'll need to either store all the values or make two passes. I suggest
> setting
>
> FS = " *(INFO)?: +"
>
> so you'll have
>
> $1 = "Name"
> $2 = "Fred"
> $3 = "1/text/..."
>
> You can store this in an array, and store the maximum length at the
> same time
>
> info[$2] = $3
> maxlen = maxlen >= length($2) ? maxlen : length($2)
>
> At the end, you split up the info into another array using split
>
> for (name in info) {
> nf = split(info[name], f, /, */)
>
> then print the first piece of information with the name, and the other
> pieces of information without the name. You use printf to do the
> printing, and specify a width on the first field. If you knew all the
> names were going to be less than 10 characters, you could write
>
> printf "%-10s %s\n", "Name", "Info"
> printf "%-10s %s\n", "----", "----"
> printf "%-10s %s\n", name, f[1]
>
> and so on. You don't know that, but you do know the names will be
> less than maxlen characters long, so you can put that into the
> format string, either like this:
>
> fmtstring = "%-" maxlen "s %s\n"
>
> printf fmtstring, name, f[1]
>
> or like this
>
> printf "%-*s %s\n", maxlen, name, f[1]
>
> The former is more portable and probably easier to use and faster.
>
> Putting it all together (but not testing it)
>
> BEGIN { FS = " *(INFO)?: +" }
> END {
> fmtstring = "%-" maxlen "s %s\n"
>
> printf fmtstring, "Name", "Info"
> printf fmtstring, "----", "----"
>
> for (name in info) {
> nf = split(info[name], f, /, */)
> printf fmtstring, name, f[1]
> for (i = 2; i <= nf; i++)
> printf fmtstring, "", f[i]
> }
> }
>
> { info[$2] = $3
> l = length($2)
> if (maxlen < l)
> maxlen = l
> }
>
>
--
Link King
king@kinger.net
Post Follow-up to this messageIn article <Pine.LNX.4.44.0402111427350.31826-100000@mogul.kinger.net>,
Link King <king@kinger.net> wrote:
% I'm close with the pointers you've given but not quite there. Two things
% in particular. One, the hosts/records are not printing out in the order
I should have mentioned that. It's a characteristic of
for (x in y)
processing that the data comes in an unpredictable order. What you need
to do if you want to preserve order is keep track of the hosts
in another array
h[NR] = $2 # at the same time as you load the other array
then loop through this array sequentially instead of using for (x in y)
for (i = 1; i <= NR; i++) {
name = h[i]
nf = split(info[name], f, /, */)
# etc
You don't have to assign h[i] to name, but it's probably a little faster
and easier to read if you do, and (the real reason) I don't have to
include a changed version of my previous posting with name changed
to h[i].
% 10.10.10.10 (xyz.abc.com) 53/open/tcp//domain
This looks like there are tabs after the colons in your input file.
You could try
BEGIN { FS = " *(INFO)?:[ \t]+" }
or use sub to remove leading whitespace before printing f[1].
--
Patrick TJ McPhee
East York Canada
ptjm@interlog.com
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.