1

I am using nawk on a pipe delimited file to print fields as index and key where some of the fields contain white space, when there is no white space everything works normal, but in case of white spaces somehow awk treats it as field separator and prints this o/p to new line. See my input below :

Input:

a|b|c d e|1|2|3
a|b c|d|1|2|2 3

Output:

Index=a|b|c 
Key=1|2|3
Index=d
Key=<null>
Index=e
Key=<null>
Index=a|b
Key=1|2|2
Index=c|d
Key=3

Expected Output:

Index=a|b|c d e
Key=1|2|3
Index=a|b c|d
Key=1|2|2 3

In short for two record 2 Index and 2 keys and keep the basic white spaces as it is.

I have to use below set of code for working on each line because there are too many fields and having huge data

    index=`echo "$line" | nawk -F '|' '
    function select_from(from,to,delim)
    {
            if (to < from) { return; };
            for (i=from;i<=to;i++)
            {
                            if (NF < i) { break;};
                            if (i < to)
                            {
                                    printf("%s%s",i,delim);
                            } else {
                                    printf("%s",i);
                            };
            };
    }
    {select_from(11,48,"|");};'`

response are correct when using some special character instead of space, but that is not correct on input data. so want to know if I can preserve space in this process.

  • so you are using | as a field separator despite it being a string you can find in any of the fields? This looks like a very bad way to maintain a file and will lead to major problems. May be better to use a CSV parser, enclose the fields in double quotes and make things easier. – fedorqui Jun 19 '15 at 13:35
2

Using awk

from=1; to=3; delimiter="|"; awk -F"$delimiter" -v from="$from" -v to="$to" '!/^[[:blank:]]*$/ {printf "Index="; for(i=from; i<=to; i++) {printf $i; if(i<to) {printf "|"};} printf "\n"; printf "Key="; for(i=to+1; i<=NF; i++) {printf $i; if(i<NF) {printf "|"};} printf "\n"}' foo

More readable

from=1; to=3; delimiter="|";
awk -F"$delimiter" -v from="$from" -v to="$to" '!/^[[:blank:]]*$/ {
    printf "Index=";
    for(i=from; i<=to; i++) {
        printf $i;
        if(i<to) {
            printf "|"
        };
    }
    printf "\n";
    printf "Key=";
    for(i=to+1; i<=NF; i++) {
        printf $i;
        if(i<NF) {
            printf "|"
        };
    }
    printf "\n"
}' foo

Example

$ cat foo
a|b|c d e|1|2|3
a|b c|d|1|2|2 3

$ from=1; to=3; delimiter="|"; awk -F"$delimiter" -v from="$from" -v to="$to" '!/^[[:blank:]]*$/ {printf "Index="; for(i=from; i<=to; i++) {printf $i; if(i<to) {printf "|"};} printf "\n"; printf "Key="; for(i=to+1; i<=NF; i++) {printf $i; if(i<NF) {printf "|"};} printf "\n"}' foo
Index=a|b|c d e
Key=1|2|3
Index=a|b c|d
Key=1|2|2 3
  • \s matches an s in nawk. Use the standard [[:blank:]] or [[:space:]] instead of the perl-isms. As far as I know, only GNU awk treats \s as whitespace. – geirha Jun 19 '15 at 8:33
1

You can use this perl command to get the expected output:

$ perl -ne 'print "Index=$1\nKey=$2\n" if /(.*?)[\s\|]([\|\d ]+)/' my_file
Index=a|b|c d e
Key=1|2|3
Index=a|b c|d
Key=1|2|2 3

I'd not use [nmg]awk for that task. Since your main script seems to be written in bash, just replace your nawk command:

#!/bin/bash

perl -ne 'print "Index=$1\nKey=$2\n" if /(.*?)[\s\|]([\|\d ]+)/' my_file

Note that you can also remove the loop creating $line in your original script.

  • can I add it within awk function – leArned Jun 19 '15 at 7:52
  • @leArned: See my update – Sylvain Pineau Jun 19 '15 at 9:01
0

Create a file and save the awk script bellow into it:

#!/usr/bin/awk -f

BEGIN { FS="|";} 
{ 
  printf"Index:";
  for(i=1;i<=NF;i++) {
       if ($i~/[[:alpha:]]/ && $(i+1)!~/[[:digit:]]/) { printf $i"|";
    }
    else if ($i~/[[:alpha:]]/ && $(i+1)~/[[:digit:]]/) {
    print $i
    }
  }

printf "\n"
} 


{ 
  printf"Key=:";
  for(i=1;i<=NF;i++) {
     if ($i~/[[:digit:]]/ && $(i+1)~/[[:digit:]]/) printf $i"|" ;
    else if ($i~/[[:digit:]]$/)  printf $i;

    }
printf "\n"
}  

Save the file, run sudo chmod +x awk-script-name.awk, and run it with the test file like so:

$ cat testfile.txt                                                                                                                    
a|b|c d e|1|2|3
a|b c|d|1|2|2 3

$ key-index-script.awk testfile.txt                                                                                                   
Index:a|b|c d e

Key=:1|2|3
Index:a|b c|d

Key=:1|2|2 3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.