Field widths based on a row


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Field widths based on a row
# 1  
Old 02-14-2016
Field widths based on a row

I want to specify field width based on the row with FTR.
I can acheive this if column width is constant with:
Code:
awk 'BEGIN  { FIELDWIDTHS = "20 7 14 30" }{print $1,$4}' file

file:
Code:
COL1                COL2   CL3           FTR
AA8                 S2     CAT2          your comments
CC7                 D1     CAT3          last comments
DD3                        CAT1          2nd to comment
BB5                        CATE4         comment

output:
Code:
COL1                 FTR
AA8                  your comments
CC7                  last comments
DD3                  2nd to comment
BB5                  comment


How can I automatically determine Field widths based on the row with FTR?
# 2  
Old 02-14-2016
Hi, try (using GNU awk):
Code:
awk '
  FNR==1 {
    s=$0
    while(match(s,/[^ ]+ */)) {   # use greedy match with field width and trailing spaces to find maximum width
      f=(f?f OFS:x) RLENGTH       # build string of field widths
      s=substr(s,RLENGTH+1)       # cut the line to to determine the next length
    }
    sub(/[0-9]*$/,1000,f)         # replace last field width with an arbitrary large number to capture the maximum width
    FIELDWIDTHS=f                 # set FIELDWIDTHS
    $0=$0                         # recalculate fields using FIELDWIDTHS
  }
  {
    print $1 $4
  }
' file


Last edited by Scrutinizer; 02-16-2016 at 12:27 PM.. Reason: Removed single excess space in output
This User Gave Thanks to Scrutinizer For This Post:
# 3  
Old 02-14-2016
For something that will work with any POSIX-conforming version of awk you might also want to consider:
Code:
#!/bin/ksh
if [ $# -lt 1 ]
then	printf 'Usage: %s field_number...\n%s %s\n' "${0##*/}" \
	    'If the last input field is to be printed,' \
	    'it must be the last output field.' >&2
	exit 1
fi
printf '%s\n' "$@" | awk -F '  +' '
FNR == NR {
	f[++nf] = $1
	next
}
FNR == 1 {
	s[1] = 1
	fc = NF
	for(i = 2; i <= fc; i++)
		w[i - 1] = (s[i] = index($0, $i)) - s[i - 1]
#	for(i=1; i<=NF; i++)
#		printf("s[%d]=%d,w[%d]=%d\n", i, s[i], i, w[i])
#	for(i = 1; i <= nf; i++)
#		printf("f[%d]=%d\n", i, f[i])
}
{	for(i = 1; i < nf; i++)
		printf("%*s", -w[f[i]], substr($0, s[f[i]], w[f[i]]))
	print (f[nf] == fc) ? substr($0, s[f[nf]]) : \
	    substr($0, s[f[nf]], w[f[nf]])
}' - file

Note that this will print an arbitrary number of input fields in any output order desired, except the last input field can only be printed as the last output field if it is printed at all. It also allows field headings to contain multiple words separated by single spaces. But to work properly, there can't be any tabs in the input and there must be at least two spaces in the heading line separating fields.

For example, if file contains:
Code:
COLUMN 1 HEADING    COL 2  COL #3        FTR
AA8                 S2     CAT2          your comments
CC7                 D1     CAT3          last comments
DD3                        CAT1          2nd to comment
BB5                        CATE4         comment

and the script above is saved in an executable file named tester in the current directory, then the command:
Code:
./tester 2 2 4

would produce the output:
Code:
COL 2  COL 2  FTR
S2     S2     your comments
D1     D1     last comments
              2nd to comment
              comment

Although written and tested using the Korn shell, this will work with any shell that accepts basic Bourne shell syntax. If you want to try this on a Solaris/SunOS system, change awk to /usr/xpg4/bin/awk or nawk.

If you want to see how the code is determining field starting positions and field widths and the fields to be printed gathered from the script command line, you can remove the # characters at the start of the four lines in the FNR == 1 clause to see the debugging output those loops print.
# 4  
Old 02-15-2016
Quote:
Originally Posted by Scrutinizer
Hi, try (using GNU awk):
Code:
awk '
  FNR==1 {
    s=$0
    while(match(s,/[^ ]+ */)) {   # use greedy match with field width and trailing spaces to find maximum width
      f=(f?f OFS:x) RLENGTH       # build string of field widths
      s=substr(s,RLENGTH+1)       # cut the line to to determine the next length
    }
    sub(/[0-9]*$/,1000,f)         # replace last field width with an arbitrary large number to capture the maximum width
    FIELDWIDTHS=f                 # set FIELDWIDTHS
    $0=$0                         # recalculate fields using FIELDWIDTHS
  }
  {
    print $1,$4
  }
' file


If I Have input with different column width (determined by Row with FTR), how can I achieve the output?
Input:
Code:
COL1                COL2   CL3           FTR
AA8                 S2     CAT2          your comments
CC7                 D1     CAT3          last comments
DD3                        CAT1          2nd to comment
BB5                        CATE4         comment
CL1                CL2   CL3           FTR
CC4                D1    CAT3          new comments
DD5                      CAT1          newcomment2

Output:
Code:
COL1                FTR
AA8                 your comments
CC7                 last comments
DD3                 2nd to comment
BB5                 comment
CL1                FTR
CC4                new comments
DD5                newcomment2

# 5  
Old 02-15-2016
Indeed, it's not quite clear to me what you're after, if the hitherto posts didn't satisfy you. Shooting in the dark:
Code:
awk '/FTR/ {FMT = index($0, $2)} {printf "%-*s%s\n", FMT, $1, $NF} ' FS="  +" file1
COL1                 FTR
AA8                  your comments
CC7                  last comments
DD3                  2nd to comment
BB5                  comment
CL1                 FTR
CC4                 new comments
DD5                 newcomment2

# 6  
Old 02-15-2016
An adaptation of the GNU awk script in post #2:
Code:
awk '
  / FTR *$/ {
    s=$0
    f=""
    while(match(s,/[^ ]+ */)) {   # use greedy match with field width and trailing spaces to find maximum width
      f=(f?f OFS:x) RLENGTH       # build string of field widths
      s=substr(s,RLENGTH+1)       # cut the line to to determine the next length
    }
    sub(/[0-9]*$/,1000,f)         # replace last field width with an arbitrary large number to capture the maximum width
    FIELDWIDTHS=f                 # set FIELDWIDTHS
    $0=$0                         # recalculate fields using FIELDWIDTHS
  }
  {
    print $1 $4
  }
' file


Last edited by Scrutinizer; 02-16-2016 at 12:27 PM.. Reason: Removed single excess space in output
These 2 Users Gave Thanks to Scrutinizer For This Post:
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. UNIX for Beginners Questions & Answers

Problem with getting awk to multiply a field by a value set based on condition of another field

Hi, So awk is driving me crazy on this one. I have searched everywhere and read man, docs and every related post Google can find and still no luck. The actual files I need to run this on are sensitive in nature, but it is the same thing as if I needed to calculate weighted grades for multiple... (15 Replies)
Discussion started by: cotilloe
15 Replies

2. Shell Programming and Scripting

Analyzing last 2 fields of 1 row and 3rd field of next row

I have the following script that will average the last two fields of each row, but im not sure how to include the 3rd field of the following row. An example of the analysis that I need to perform from the input - (66.61+58.01+54.16)/3 awk '{sum=cnt=0; for (i=13;i<=NF;i++) { sum+=$i; cnt++... (1 Reply)
Discussion started by: ncwxpanther
1 Replies

3. Shell Programming and Scripting

Replacing field based on the value of other field

Hi Team, In the below input file, if I have the value 23,24,25 then for those records 1st field value should get updated from "a" to "b". I also want to pass these values in file as input as it can be done dynamically. Tried awk commands but not getting desired output.Using SunOS 5.10 version.... (14 Replies)
Discussion started by: weknowd
14 Replies

4. Shell Programming and Scripting

awk to adjust coordinates in field based on sequential numbers in another field

I am trying to output a tab-delimited result that uses the data from a tab-delimited file to combine and subtract specific lines. If $4 matches in each line then the first matching sequential $6 value is added to $2, unless the value is 1, then the original $2 is used (like in the case of line... (3 Replies)
Discussion started by: cmccabe
3 Replies

5. Shell Programming and Scripting

awk to update value in field based on another field

In the tab-delimeted input file below I am trying to use awk to update the value in $2 if TYPE=ins in bold, by adding the value of HRUN= in italics. In the below since in line 1 TYPE=ins the 117282541 value in $2 has 6 added because that is the value of HRUN=. Hopefully the awk is a start but I... (2 Replies)
Discussion started by: cmccabe
2 Replies

6. Shell Programming and Scripting

Splitting single row into multiple rows based on for every 10 digits of last field of the row

Hi ALL, We have requirement in a file, i have multiple rows. Example below: Input file rows 01,1,102319,0,0,70,26,U,1,331,000000113200000011920000001212 01,1,102319,0,1,80,20,U,1,241,00000059420000006021 I need my output file should be as mentioned below. Last field should split for... (4 Replies)
Discussion started by: kotra
4 Replies

7. Shell Programming and Scripting

Trying to remove duplicates based on field and row

I am trying to see if I can use awk to remove duplicates from a file. This is the file: -==> Listvol <== deleting /vol/eng_rmd_0941 deleting /vol/eng_rmd_0943 deleting /vol/eng_rmd_0943 deleting /vol/eng_rmd_1006 deleting /vol/eng_rmd_1012 rearrange /vol/eng_rmd_0943 ... (6 Replies)
Discussion started by: newbie2010
6 Replies

8. UNIX for Dummies Questions & Answers

awk - Summing a field based on another field

So, I need to do some summing. I have an Apache log file with the following as a typical line: 127.0.0.1 - frank "GET /apache_pb.gif HTTP/1.0" 200 2326 Now, what I'd like to do is a per-minute sum. So, I can have awk tell me the individual minutes, preserving the dates(since this is a... (7 Replies)
Discussion started by: treesloth
7 Replies

9. Shell Programming and Scripting

Find top N values for field X based on field Y's value

I want to find the top N entries for a certain field based on the values of another field. For example if N=3, we want the 3 best values for each entry: Entry1 ||| 100 Entry1 ||| 95 Entry1 ||| 30 Entry1 ||| 80 Entry1 ||| 50 Entry2 ||| 40 Entry2 ||| 20 Entry2 ||| 10 Entry2 ||| 50... (1 Reply)
Discussion started by: FrancoisCN
1 Replies

10. Shell Programming and Scripting

How to insert data befor some field in a row of data depending up on values in row

Hi I need to do some thing like "find and insert before that " in a file which contains many records. This will be clear with the following example. The original data record should be some thing like this 60119827 RTMS_LOCATION_CDR INSTANT_POSITION_QUERY 1236574686123083rtmssrv7 ... (8 Replies)
Discussion started by: aemunathan
8 Replies
Login or Register to Ask a Question