LinuxQuestions.org
Visit Jeremy's Blog.
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 06-27-2012, 09:21 PM   #1
micyew
LQ Newbie
 
Registered: Jan 2011
Posts: 21

Rep: Reputation: 0
Convert row to column


Hi,

Not sure can I do this in awk....

I have the following text file where each field in their own row..

Device ID: SEP001121111111
IP address: 1.1.1.1
Platform: Cisco IP Phone 7970, Capabilities: Host Phone Two-port Mac Relay
Device ID: SEP00115C222222
IP address: 2.2.2.2
Platform: Cisco IP Phone 7940, Capabilities: Host Phone Two-port Mac Relay
Device ID: SEP000D29033333
IP address: 3.3.3.3
Platform: Cisco IP Phone 7960, Capabilities: Host Phone Two-port Mac Relay


I want it to appear as a csv with 3 fields in each record..

Device ID: SEP001121111111;IP address: 1.1.1.1;Platform: Cisco IP Phone 7970, Capabilities: Host Phone Two-port Mac Relay
Device ID: SEP00115C222222;IP address: 2.2.2.2;Platform: Cisco IP Phone 7940, Capabilities: Host Phone Two-port Mac Relay
Device ID: SEP000D29033333;IP address: 3.3.3.3;Platform: Cisco IP Phone 7960, Capabilities: Host Phone Two-port Mac Relay

How do I do this in awk? If can't, any other script that can do this?

thanks in a million...
 
Old 06-27-2012, 10:00 PM   #2
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Code:
#!/bin/bash
#   Daniel B. Martin   Jun12
#
#   To execute this program, launch a terminal sesson and enter:
#   bash /home/daniel/Desktop/LQfiles/dbm412.bin
#
# This program inspired by ...
# http://www.linuxquestions.org/questions/programming-9/
#  convert-row-to-column-4175413752/
 
# File identification  
InFile='/home/daniel/Desktop/LQfiles/dbm412inp.txt'
OutFile='/home/daniel/Desktop/LQfiles/dbm412out.txt'

tr '\n' ';' < $InFile  \
|sed 's/Device ID:/\nDevice ID:/g' \
|sed '1d' \
|sed 's/;$//' \
> $OutFile

echo
echo "Our work is done.  Punch out.  Go home."
echo 'Normal end of job.'
echo 'Execution ended.'
echo

exit
Daniel B. Martin
 
Old 06-27-2012, 10:11 PM   #3
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
If the fields do not contain semicolons, then
Code:
awk '(tolower($1) == "device") { if (FNR > 1) printf("\n%s", $0) ; else printf("%s", $0); next } { printf(";%s", $0) } END { printf("\n") }'
should do the trick.

To explain why and how it works, here it is in broken-down form:
Code:
awk '(tolower($1) == "device") {
          if (FNR > 1)
               printf("\n%s", $0)
          else
               printf("%s", $0)
          next
     }

     {
          printf(";%s", $0)
     }

     END {
          printf("\n")
     }'
The idea is that whenever the input line starts with Device (ignoring case via converting it to lower case), it will also start a new output line. If it is the very first line of input, we know it is at the very start of the output, so we skip the newline. The next tells awk to skip the rest of the rules, and check the next input line instead.

The middle one prints a semicolon and the input line, without any newline.

The final one is only run when all input lines have been processed. It adds the newline at end.

You could also use tr and sed to get the exact same effect:
Code:
( tr '\n' ';'
  echo
) | (
  sed -e 's|;\([Dd][Ee][Vv][Ii][Cc][Ee][\t\v\f\r ]\)|\n\1|g'
  echo
)
where the first echo adds the newline at end so that all sed variants actually process the line, and the second adds the final newline to the output. Note that if you have the input in a file, you need to use tr '\n' ';' < file .

A third approach would simply replace two out of three newlines with semicolons:
Code:
awk '{ if (FNR % 3 == 0) printf("%s\n", $0) ; else printf("%s;", $0) }'
 
1 members found this post helpful.
Old 06-28-2012, 05:09 AM   #4
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
Code:
$ split -l 3 file
$ paste -d";" -s x*
Device ID: SEP001121111111;IP address: 1.1.1.1;Platform: Cisco IP Phone 7970, Capabilities: Host Phone Two-port Mac Relay
Device ID: SEP00115C222222;IP address: 2.2.2.2;Platform: Cisco IP Phone 7940, Capabilities: Host Phone Two-port Mac Relay
Device ID: SEP000D29033333;IP address: 3.3.3.3;Platform: Cisco IP Phone 7960, Capabilities: Host Phone Two-port Mac Relay
Well, yes – the temporary files need to be removed afterwards. I miss an option in split to output the names of the created files, which could be used to remove them easily.
 
1 members found this post helpful.
Old 06-28-2012, 06:07 AM   #5
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by Reuti View Post
I miss an option in split to output the names of the created files, which could be used to remove them easily.
How about
Code:
Patch on top of coreutils-8.17 to add --print option
to output the file names to standard output.
Use --print= or --print="" to use ASCII NUL separator.

diff -Naur old/src/split.c new/src/split.c
--- old/src/split.c	2012-05-10 11:24:16.000000000 +0300
+++ new/src/split.c	2012-06-28 13:51:35.900787821 +0300
@@ -55,6 +55,10 @@
 /* Process ID of the filter.  */
 static int filter_pid;
 
+/* File handle for printing file names. */
+static FILE *print_handle = NULL;
+static int print_delimiter = '\n';
+
 /* Array of open pipes.  */
 static int *open_pipes;
 static size_t open_pipes_alloc;
@@ -119,6 +123,7 @@
 {
   VERBOSE_OPTION = CHAR_MAX + 1,
   FILTER_OPTION,
+  PRINT_OPTION,
   IO_BLKSIZE_OPTION,
   ADDITIONAL_SUFFIX_OPTION
 };
@@ -136,6 +141,7 @@
    ADDITIONAL_SUFFIX_OPTION},
   {"numeric-suffixes", optional_argument, NULL, 'd'},
   {"filter", required_argument, NULL, FILTER_OPTION},
+  {"print", optional_argument, NULL, PRINT_OPTION},
   {"verbose", no_argument, NULL, VERBOSE_OPTION},
   {"-io-blksize", required_argument, NULL,
    IO_BLKSIZE_OPTION}, /* do not document */
@@ -219,6 +225,7 @@
   -d, --numeric-suffixes[=FROM]  use numeric suffixes instead of alphabetic.\n\
                                    FROM changes the start value (default 0).\n\
   -e, --elide-empty-files  do not generate empty output files with '-n'\n\
+      --print[=DELIMITER] print file names to standard output\n\
       --filter=COMMAND    write to shell COMMAND; file name is $FILE\n\
   -l, --lines=NUMBER      put NUMBER lines per output file\n\
   -n, --number=CHUNKS     generate CHUNKS output files.  See below\n\
@@ -358,6 +365,11 @@
 static int
 create (const char *name)
 {
+  if (print_handle)
+    {
+      fputs (name, print_handle);
+      fputc (print_delimiter, print_handle);
+    }
   if (!filter_command)
     {
       if (verbose)
@@ -1250,6 +1262,12 @@
           elide_empty_files = true;
           break;
 
+        case PRINT_OPTION:
+          print_handle = stdout;
+          if (optarg)
+             print_delimiter = optarg[0];
+          break;
+
         case FILTER_OPTION:
           filter_command = optarg;
           break;
You could always ask for something like the above to be included in coreutils. If you use split often, and miss that option, others probably miss it too. I don't use it that often, so I'm not sure if the interface is what you'd prefer, or would --print, --print0, --fprint=FILE, --fprint0=FILE make more sense. It is literally trivial to modify; I chose a very versatile way to implement it. I think print_delimiter should probably be a string, though; with NULL string indicating a single NUL byte. Just let me know, and I'd be happy to provide a patch you can push upstream.

If your comment was just idle banter, don't worry; I just hadn't looked at Coreutils for quite a while so I thought it was a perfect reason to download the latest sources and look at it.

Edited to add: Ignore the patch above. It works, but existing --filter option can trivially achieve the same functionality:
Code:
split --filter='printf "%s\n" "$FILE"; exec cat > "$FILE"' ...

Last edited by Nominal Animal; 06-28-2012 at 06:48 AM.
 
Old 06-28-2012, 01:29 PM   #6
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
Quote:
Originally Posted by Nominal Animal View Post
If your comment was just idle banter, don't worry; I just hadn't looked at Coreutils for quite a while so I thought it was a perfect reason to download the latest sources and look at it.

Edited to add: Ignore the patch above. It works, but existing --filter option can trivially achieve the same functionality:
Code:
split --filter='printf "%s\n" "$FILE"; exec cat > "$FILE"' ...
Seems to be a new option, I wasn’t aware of --filter. Thanks for pointing it out. Reminds of rereading certain man pages from time to time.
 
Old 06-28-2012, 02:20 PM   #7
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by Nominal Animal View Post
... existing --filter option can trivially achieve the same functionality:
Code:
split --filter='printf "%s\n" "$FILE"; exec cat > "$FILE"' ...
I can't make this work. Please give more information and/or examples. Is it possible that my Ubuntu system lacks the --filter option? I can execute info coreutils 'split invocation' and don't see it.

Daniel B. Martin
 
Old 06-28-2012, 02:32 PM   #8
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
Which version are you using: split --version I compiled 8.17 and there it is present and working nicely.
 
Old 06-28-2012, 03:13 PM   #9
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by Reuti View Post
Which version are you using: split --version I compiled 8.17 and there it is present and working nicely.
Compiled? Compiled what? I write a program in REXX or BASH and run it. These are not compiled, they are (to the best of my knowledge) interpreted.

Daniel B. Martin
 
Old 06-28-2012, 03:20 PM   #10
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
8.17 of coreutils.
 
Old 06-28-2012, 03:25 PM   #11
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
danielbmartin, run split --version to see the version number. Coreutils-8.17 is the latest version (released in May). Reuti compiled it from sources, probably to test the patch I wrote above.

I can confirm the --filter option is available in Coreutils-8.13, split (GNU coreutils) 8.13. It is also listed in both the info and man pages for this version.
 
1 members found this post helpful.
Old 06-28-2012, 05:23 PM   #12
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by Nominal Animal View Post
... run split --version to see the version number. Coreutils-8.17 is the latest version (released in May).
Code:
daniel@daniel-desktop:~$ split --version
split (GNU coreutils) 7.4
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Torbjörn Granlund and Richard M. Stallman.
I apply Ubuntu updates as soon as they become available. May I expect that my system will receive a new Coreutils in the near future?

Daniel B. Martin
 
Old 06-28-2012, 05:55 PM   #13
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
Quote:
Originally Posted by Nominal Animal View Post
Reuti compiled it from sources, probably to test the patch I wrote above.
Well, no. I compiled it as you mentioned the --filter option. It has various other applications like: insert an additional line after every 3rd rows:
Code:
$ split -l 3 --filter="(cat; echo '--------') >> OUTFILE" INFILE
Even if one uses these tools for years, sometimes new options surprise me.
 
Old 06-28-2012, 06:09 PM   #14
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
And going back to the original question, there are no temporary files necessary any more:
Code:
$ split -l 3 --filter="paste -s -d ';' >> OUTFILE" INFILE
 
Old 06-29-2012, 04:10 AM   #15
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by danielbmartin View Post
May I expect that my system will receive a new Coreutils in the near future?
Not to Lucid Lynx.

Distributions tend to keep the features at the time of the release, and just backport bug fixes to the packages. It is a good strategy, and keeps the dependencies between packages stable.

Note that Lucid Lynx support ends in April 2013, so you'll have to upgrade anyway in the next year or so.
 
1 members found this post helpful.
  


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
[SOLVED] find a null value in a row/column and delete entire row umix Linux - Newbie 10 10-13-2011 01:26 AM
Transposing only part of row into column Mehidi Programming 1 07-08-2011 05:53 AM
[ask awk] remove certain row in a column dhodho Programming 18 06-08-2010 09:36 AM
transpose row to column? resolute155 Programming 3 09-07-2009 02:29 PM
Transposing a column into a row mayyash Linux - General 1 09-30-2005 02:23 AM

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

All times are GMT -5. The time now is 05:21 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