LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-28-2013, 06:20 PM   #1
sn00gans
LQ Newbie
 
Registered: May 2013
Posts: 4

Rep: Reputation: Disabled
Bash/AWK - Transposing, indexing, newbie at if/else.


Hello everyone,

I'm trying to index this file using awk:

INPUT:
device,cookedvalue,timestamp,sequence
hda,11,2013.05.20:09:36:00,1
hdb,12,2013.05.20:09:36:00,1
hdc,13,2013.05.20:09:36:00,1
mem,101,2013.05.20:09:36:00,1
page,1001,2013.05.20:09:36:00,1
hda,21,2013.05.20:09:36:01,2
hdb,22,2013.05.20:09:36:01,2
hdc,23,2013.05.20:09:36:01,2
mem,201,2013.05.20:09:36:01,2
page,2001,2013.05.20:09:36:01,2

DESIRED OUTPUT:
sequence,hda,hdb,hdc,mem,page,timestamp
11,12,13,101,1001,2013.05.20:09:36:00
21,22,23,201,2002,2013.05.20:09:36:01

So I basically want to transpose the first column into the first row, and index each row according the the sequence column.

Since I've been using awk a lot, I thought I'd use it. But I've run into a roadblock. Here's the code I've been using:

Code:
awk -v seq=1 '{ FS = "," }
{ if ( $4 == seq ) 
    {printf $2",";timestamp = $3} 
  else 
    {seq+1;printf $3"\n";printf $2","}}' gen2.csv
I figured the code would work like this (pseudocode)

Code:
sequence=1
   read each record
      if  $4 = sequence
	append $2+"," to output
	timestamp = $3
      else
	sequence++
	append $3+"\n" to output
	append $2+"," to output
However, it's not working. This is the output I get:

,12,13,101,1001,2013.05.20:09:36:01
21,2013.05.20:09:36:01
22,2013.05.20:09:36:01
23,2013.05.20:09:36:01
201,2013.05.20:09:36:01
2001,
,
,
,
,

I think the issue is either within the else statement or that awk's if/else function doesn't automatically repeat (i.e. go back to the 'if' part of the function).

Any suggestions?

TIA

Last edited by sn00gans; 05-28-2013 at 06:26 PM.
 
Old 05-28-2013, 06:25 PM   #2
sn00gans
LQ Newbie
 
Registered: May 2013
Posts: 4

Original Poster
Rep: Reputation: Disabled
edit: Reply to this thread != reply to another thread.

Last edited by sn00gans; 05-28-2013 at 06:28 PM. Reason: is an idiot. :(
 
Old 05-28-2013, 07:37 PM   #3
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,784

Rep: Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083
I don't really understand what you are trying to do, but there is an inconsistency between your code and psuedocode:

Quote:
Originally Posted by sn00gans View Post
Here's the code I've been using:

Code:
awk -v seq=1 '{ FS = "," }
{ if ( $4 == seq ) 
    {printf $2",";timestamp = $3} 
  else 
    {seq+1;printf $3"\n";printf $2","}}' gen2.csv
I figured the code would work like this (pseudocode)

Code:
sequence=1
   read each record
      if  $4 = sequence
	append $2+"," to output
	timestamp = $3
      else
	sequence++
	append $3+"\n" to output
	append $2+"," to output
seq+1; has no effect, seq++; would be the correct awk statement (seq += 1; would also work). Also, the assignment to FS is repeated for every record as well, you should put BEGIN as the pattern before the action to indicate it only happens once. Or you can set it using the -F option, as in: awk -F, -v seq=1 '{...}'
 
Old 05-28-2013, 08:16 PM   #4
sn00gans
LQ Newbie
 
Registered: May 2013
Posts: 4

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by ntubski View Post
I don't really understand what you are trying to do, but there is an inconsistency between your code and psuedocode:
Each record represents a counter representing a metric (hda, hdb, memory, etc.)
The cookedvalue column represents a value pertaining to the record's metric.
The output should print out all the cookedvalues for all metrics that have the same sequence all on the same line.
The output file is then going to be parsed by another program that a co-worker is using that plots the resulting data by indexing the timestamp.

To do this:
Code:
1. AWK reads a record.
  1a. Check to see if the sequence field is 1.
  1b.    If it is, 
             print the cookedvalue of that record followed by a comma; 
             remember the record's timestamp.
  1c.      (This way, every time the record is 1, it will print cookedvalue after cookedvalue)
  1d.    If it isn't, 
            then print the timestamp at the end of the current line; 
            create a new line; 
            print the current record's cookedvalue;
            increase the sequence field checker by 1.
  1e. go back to 1a.
It seems that my logic on step 1d is faulty. It loops the "print timestamp + newline, print cookedvalue" section.

Does that make more sense now?
 
Old 05-29-2013, 08:50 AM   #5
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,784

Rep: Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083
How about this:
Code:
awk -F, -v seq=1 '
 NR == 1 { print "sequence,hda,hdb,hdc,mem,page,timestamp" }
 NR > 1 {
    if ($4 != seq) {
       print timestamp;
       seq = $4;
    }
    printf("%s,", $2);
    timestamp = $3;
 }
 END {print timestamp}' gen2.csv
I think your main problem is that you forgot to account for the header line, so seq was never matching the sequence number.
 
1 members found this post helpful.
Old 05-29-2013, 09:28 AM   #6
sn00gans
LQ Newbie
 
Registered: May 2013
Posts: 4

Original Poster
Rep: Reputation: Disabled
Wow, thanks SO much. That's awesome. I sort of see how you did that; besides the header issue, it looks like you flipped my if/else logic.

Thanks again, I'm a complete newbie when it comes to scripting and logic loops.
 
Old 05-29-2013, 11:41 AM   #7
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
We all seemed to have missed the sequence number at the beginning (not sure if important??):
Code:
awk -F, 'BEGIN{ print "sequence,hda,hdb,hdc,mem,page,timestamp" }
         x != "page"{
                     printf ++seq FS;
                     x="page"
         }
         NR > 1{
                if($1 == "page"){
                                 x = "";
                                 _ = $3 RT
                }else
                                 _ = "";
                printf "%s",$2 FS _
         }' file
 
Old 05-29-2013, 02:27 PM   #8
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,784

Rep: Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083
Quote:
Originally Posted by sn00gans View Post
I sort of see how you did that; besides the header issue, it looks like you flipped my if/else logic.
Not flipped so much as combined the common parts:
Code:
      if  $4 = sequence
	append $2+"," to output
	timestamp = $3
      else
	sequence++
	append timestamp+"\n" to output # $3 was written, but timestamp was meant
	append $2+"," to output
===> # can put timestamp assignment in else branch without causing trouble
      if  $4 = sequence
	append $2+"," to output
	timestamp = $3
      else
	sequence++
	append timestamp+"\n" to output
	append $2+"," to output
	timestamp = $3 # harmless
===> # note that blue parts are common:
      if  $4 = sequence
        ;
      else
	sequence++
	append timestamp+"\n" to output
      append $2+"," to output
      timestamp = $3
Quote:
Originally Posted by grail View Post
We all seemed to have missed the sequence number at the beginning (not sure if important??):
Hmm, true. It's not in the DESIRED OUTPUT of OP. I would guess it's actually the "sequence" from the header line that should be removed since:
Quote:
The output file is then going to be parsed by another program that a co-worker is using that plots the resulting data by indexing the timestamp.
 
Old 05-30-2013, 01:34 AM   #9
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
True, so my question to the OP is .... Is the header incorrect, ie the sequence should be removed? Currently we have 7 items in the header and only 6 in the data lines or recommended output.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Some help with BASH and awk surferdude Programming 4 07-26-2012 12:00 PM
[SOLVED] bash/awk: What is going on here? tmerriam Programming 6 04-16-2012 06:19 PM
AWK/BASH: get nth line from a file by getline feed to actions in a same awk line cristalp Programming 3 11-23-2011 11:38 AM
[SOLVED] call awk from bash script behaves differently to awk from CLI = missing newlines titanium_geek Programming 4 05-26-2011 09:06 PM
need help with bash and awk stympman Programming 3 11-01-2008 06:12 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:28 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration