Control-break"ish" in awk


 
Thread Tools Search this Thread
Top Forums UNIX for Dummies Questions & Answers Control-break"ish" in awk
# 1  
Old 01-19-2015
Control-break"ish" in awk

Hi,

input:
Code:
1|Bob
2|Bob
Ref|Bob
3|Rick
7|Rick
Ref|Rick

I am trying to append a "*" field to the record containing "Ref" in $1, only if the previous $1 with a common $2 have a value <4.

ouput:
Code:
1|Bob
2|Bob
Ref|Bob|*
3|Rick
7|Rick
Ref|Rick

The first subgroup ("Bob") shows $1 with only values <4, so a "*" is appended at the record "Ref".
The second subgroup ("Rick") shows one value >4 and is thus unchanged.

I read a couple of tutorials dealing with control-break programs, but they are all for counting (which is not my goal).

If someone could put me on track :-)

My attempt so far:
Code:
BEGIN{FS=OFS="|"}
{a[$2]++}
END{
   for(i in a){
      if($1 <4){
         if($1 ~ /Ref/){print $0 "|\*"}
      }
      else{print $0}
   }
}


Last edited by beca123456; 01-19-2015 at 02:19 AM..
# 2  
Old 01-19-2015
Hello beca123456,

Could you please try and let us know if this helps.
Code:
awk -F"|" 'FNR==NR{X[$2]+=$1;next} {A=$2;{if(X[A]<8 && $1=="Ref"){$0=$0 OFS "*";print $0} else {print $0}}}' OFS="|"  Input_file Input_file

Output will be as follows.
Code:
1|Bob
2|Bob
Ref|Bob|*
3|Rick
7|Rick
Ref|Rick

EDIT: Adding a non oneliner form for solution.
Code:
awk -F"|" '
                FNR==NR {
                                X[$2]+=$1;
                                next
                        }
                        {
                                A=$2;
                                                {
                                                        if(X[A]<8 && $1=="Ref")
                                                        {
                                                                $0=$0 OFS "*";
                                                                print $0
                                                        }
                                                        else
                                                        {
                                                                print $0
                                                        }
                                                }
                        }
          ' OFS="|"  Input_file Input_file


Thanks,
R. Singh

Last edited by RavinderSingh13; 01-19-2015 at 02:26 AM.. Reason: Added a non one liner form for solution
# 3  
Old 01-19-2015
Thanks it works !

However, I don't get it. What is the point of using FNR=NR if the two input files are the same?
Usually we use this trick when 2 files are different for comparing them, no?

Also, when you write
Code:
if(X[A]<8

, you mean
Code:
if(X[A]<4

, no?
# 4  
Old 01-19-2015
Hello beca123456,

As per your request each 1st field with respect to 2nd field should be less than 4, so I have taken field 2 as index and added all it's first fields(Assuming as per given data like there will be only 2 fields with values and one will be for ref) and if sum is less than 8 means we are good to add * at end else don't do anything. Now about your query to give Input_file 2 times, in awk we can read multiple files(same like we can multiple arguments to a script). It will read files one by one. Here I want to mention I have put condition FNR==NR this condition will be true only when first file will be read as FNR value will be reset to one each time it goes to read next file but NR value will be keep on increasing even file name is changed, so it will like as follows.
Code:
awk '{print FNR ":" NR}' Input_file Input_file
1:1
2:2
3:3
4:4
5:5
6:6
1:7
2:8
3:9
4:10
5:11
6:12

Notice the highlighted ones for FNR values. I hope this helps, if you have any query kindly do let me know, will try to solve.


Thanks,
R. Singh
# 5  
Old 01-19-2015
Sorry, it doesn't work actually ! I didn't explain clearly at first.

Let's say we have this input instead:
Code:
1|Bob
3|Bob
Ref|Bob
5|Rick
1|Rick
Ref|Rick

The output should be the same as before:
Code:
1|Bob
3|Bob
Ref|Bob|*
5|Rick
1|Rick
Ref|Rick

But with your formula I got the second ref record tagged as well:
Code:
1|Bob
3|Bob
Ref|Bob|*
5|Rick
1|Rick
Ref|Rick|*

I am not trying to sum any value. The numbers are just tags.
Looking at the input file, we have 2 groups:
- the "Bob" group (record 1, 2, and 3)
- the "Rick" group (record 4, 5, and 6)
For each group, if ALL the $1 values (assessed individually) are <4, then the record with $1=Ref should be appended a "*" sign (like for the "Bob" group).
To the contrary, if at least one $1 value of a same group is >4, then all the record from this group should be unchanged (including the Ref record).
# 6  
Old 01-19-2015
Hello beca123456,

Sorry for confusion, could you please try this following with same concept and little editing with conditions.
Code:
awk -F"|" 'FNR==NR{i=0;{if($1 ~ /Ref/){next};X[$2]=$1>3?X[$2]+1:X[$2]+0;next}}; {A=$2;{if(X[A] >= 1 && $1=="Ref"){;print $0} else if(X[A] < 1 && $1=="Ref"){$0=$0 OFS "*";print $0} else {print $0}}}' OFS="|"  Input_file Input_file

Let's say we have 2 senarios as follows.
Code:
cat test17
3|Bob
1|Bob
Ref|Bob
2|Rick
3|Rick
Ref|Rick
 
awk -F"|" 'FNR==NR{i=0;{if($1 ~ /Ref/){next};X[$2]=$1>3?X[$2]+1:X[$2]+0;next}}; {A=$2;{if(X[A] >= 1 && $1=="Ref"){;print $0} else if(X[A] < 1 && $1=="Ref"){$0=$0 OFS "*";print $0} else {print $0}}}' OFS="|"  test17 test17
 
3|Bob
1|Bob
Ref|Bob|*
2|Rick
3|Rick
Ref|Rick|*

2nd senario:
Code:
cat test17
4|Bob
1|Bob
Ref|Bob
2|Rick
4|Rick
Ref|Rick
 
 
awk -F"|" 'FNR==NR{i=0;{if($1 ~ /Ref/){next};X[$2]=$1>3?X[$2]+1:X[$2]+0;next}}; {A=$2;{if(X[A] >= 1 && $1=="Ref"){;print $0} else if(X[A] < 1 && $1=="Ref"){$0=$0 OFS "*";print $0} else {print $0}}}' OFS="|"  test17 test17
 
4|Bob
1|Bob
Ref|Bob
2|Rick
4|Rick
Ref|Rick

EDIT: Adding a non oneliner solution for same.
Code:
awk -F"|" 'FNR==NR      {
                                i=0;
                        {
                                if($1 ~ /Ref/)
                                                {
                                                        next
                                                };
                                X[$2]=$1>3?X[$2]+1:X[$2]+0;next
                        }
                        };
                        {
                                A=$2;
                        {
                                if(X[A] >= 1 && $1=="Ref")
                                                {
                                                        print $0
                                                }
                                else if(X[A] < 1 && $1=="Ref")
                                                {
                                                        $0=$0 OFS "*";
                                                        print $0
                                                }
                                else
                                                {
                                                        print $0
                                                }
                        }
                        }
           ' OFS="|" test17 test17


Thanks,
R. Singh

Last edited by RavinderSingh13; 01-19-2015 at 06:30 AM.. Reason: Added a non oneliner form + added a few lines with spaces now
# 7  
Old 01-19-2015
Still not working !!!

Using your code:
input:
Code:
1|Bob
3|Bob
Ref|Bob
5|Rick
1|Rick
Ref|Rick

output:
Code:
1|Bob
3|Bob
Ref|Bob|*
5|Rick
1|Rick
Ref|Rick|*

I should get:
Code:
1|Bob
3|Bob
Ref|Bob|*
5|Rick
1|Rick
Ref|Rick

Let's me explain again with another example:
Code:
1|Bob
3|Bob
Ref|Bob
2|Rick
5|Rick
1|Rick
Ref|Rick
7|Paul
Ref|Paul

Here we have 3 groups "Bob", "Rick" and "Paul'.
* 1st group:
1st record, value of $1 is 1 (i.e. <4)
2nd record, value of $1 is 3 (i.e. <4)
=> as all $1 are <4, we can add "*" at the last record of the group (the one starting with Ref)

* 2nd group:
1st record of this group, value of $1 is 2 (i.e. <4)
2nd record of this group, value of $1 is 5 (i.e >4)
=> at least one value of the group is >4, the last record of the group (the one starting with Ref), must remain unchanged (no matter the value of $1 in the 3rd record of the group)

* 3rd group:
1st record of this group, value of $1 is 7 (i.e. >4)
=> the last record of the group (the one starting with Ref), must remain unchanged.

We should then obtain:
Code:
1|Bob
3|Bob
Ref|Bob|*
2|Rick
5|Rick
1|Rick
Ref|Rick
7|Paul
Ref|Paul

 
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Bash script - Print an ascii file using specific font "Latin Modern Mono 12" "regular" "9"

Hello. System : opensuse leap 42.3 I have a bash script that build a text file. I would like the last command doing : print_cmd -o page-left=43 -o page-right=22 -o page-top=28 -o page-bottom=43 -o font=LatinModernMono12:regular:9 some_file.txt where : print_cmd ::= some printing... (1 Reply)
Discussion started by: jcdole
1 Replies

2. UNIX for Dummies Questions & Answers

Find a string across line break (because of "segmentation fault core dumped")

Hi, thanks to a precedent post, and thanks to the reply of derekludwig of the forum, I have convert my first awk command as : test.txt is : AAAAAGHIJKLAjKMEFJKLjklABCDJkLEFGHIJKL awk -f findstring.awk test.txt > textreturn.txtfindstring.awk is : BEGIN{ SLENGTH = 3 } { ... (3 Replies)
Discussion started by: thewizarde6
3 Replies

3. Tips and Tutorials

How to do a "Control Break" (Algorithm)

A vast amount of problems asked in "Shell Programming an Scripting" can be traced back to be an application of a basic algorithm called a Control Break. Every programmer - and script writers are programmers nonetheless - should immediately recognize problems of this sort and know how to deal with... (1 Reply)
Discussion started by: bakunin
1 Replies

4. Shell Programming and Scripting

how to use "cut" or "awk" or "sed" to remove a string

logs: "/home/abc/public_html/index.php" "/home/abc/public_html/index.php" "/home/xyz/public_html/index.php" "/home/xyz/public_html/index.php" "/home/xyz/public_html/index.php" how to use "cut" or "awk" or "sed" to get the following result: abc abc xyz xyz xyz (8 Replies)
Discussion started by: timmywong
8 Replies

5. Shell Programming and Scripting

awk command to replace ";" with "|" and ""|" at diferent places in line of file

Hi, I have line in input file as below: 3G_CENTRAL;INDONESIA_(M)_TELKOMSEL;SPECIAL_WORLD_GRP_7_FA_2_TELKOMSEL My expected output for line in the file must be : "1-Radon1-cMOC_deg"|"LDIndex"|"3G_CENTRAL|INDONESIA_(M)_TELKOMSEL"|LAST|"SPECIAL_WORLD_GRP_7_FA_2_TELKOMSEL" Can someone... (7 Replies)
Discussion started by: shis100
7 Replies

6. Shell Programming and Scripting

Simplify Bash Script Using "sed" Or "awk"

Input file: 2 aux003.net3.com error12 6 awn0117.net1.com error13 84 aux008 error14 29 aux001.ha.ux.isd.com error12 209 aux002.vm.ux.isd.com error34 21 alx0027.vm.net2.com error12 227 dux001.net5.com error123 22 us008.dot.net2.com error121 13 us009.net2.com error129Expected Output: 2... (4 Replies)
Discussion started by: sQew
4 Replies

7. Shell Programming and Scripting

"last" in perl vs "break" elsewhere

Is there a functional difference between the two statements? (4 Replies)
Discussion started by: thmnetwork
4 Replies

8. Shell Programming and Scripting

cat $como_file | awk /^~/'{print $1","$2","$3","$4}' | sed -e 's/~//g'

hi All, cat file_name | awk /^~/'{print $1","$2","$3","$4}' | sed -e 's/~//g' Can this be done by using sed or awk alone (4 Replies)
Discussion started by: harshakusam
4 Replies

9. Shell Programming and Scripting

help for saving vertical datas to horizontal with "awk" or "cut"

hi, i have a file having datas like that ./a.txt 12344 12345 12346 12347 ..... ..... ... i want to save this datas to another file like that ./b.txt 12344 12345 12346 12347 ... ... ... i think awk can make this but how? :) waiting for ur help. (3 Replies)
Discussion started by: mercury
3 Replies

10. UNIX for Dummies Questions & Answers

Explain the line "mn_code=`env|grep "..mn"|awk -F"=" '{print $2}'`"

Hi Friends, Can any of you explain me about the below line of code? mn_code=`env|grep "..mn"|awk -F"=" '{print $2}'` Im not able to understand, what exactly it is doing :confused: Any help would be useful for me. Lokesha (4 Replies)
Discussion started by: Lokesha
4 Replies
Login or Register to Ask a Question