6

I know this might be an old problem and it has been solved by many people; however, my version requires a little bit of twist.

So I have a file, I'll call it quest. For simiplicity here, it just have 4 entry:

John

Christina

Christine

Tom

Now, I want to use awk to get the longest name in this file and I want it to return both Christina and Christine.

This is what I have so far:

<quest awk '{ if(length>x) {x =length; y=$0} } END {print y}'

And it will just return Christina. I think it can be done with just one line but I am having troubles to come up with a clever way to do it. And I appreciate if you can help! And of course, I prefer a single line.

1
  • wrt I prefer a single line - any program can be written in a single line so that's not a useful criteria for a solution. Also, using redirection for your input instead of specifying the file name as an awk arg removes your availability of FILENAME in the script and makes it harder to enhance in future if your requirements change in some ways. Commented Apr 13, 2014 at 23:48

4 Answers 4

7

You can maybe use the following:

$ awk '{cur=length($0)} FNR==NR{max=(cur>max?cur:max); next} cur==max' file file
Christina
Christine

It loops through the file twice with the syntax awk '...' file file:

  • First time to get the maximum value - and store it in the max variable. This is the FNR==NR {} block, that ends with a next to stop processing the current line. More info in Idiomatic awk.
  • Second time to print those lines whose length is max.

Note the usage of max=(cur>max?cur:max to set the maximum. It is a ternary operator that can be read like this: to set max check if cur>max. If that is true, max=length($0); otherwise, max=max.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your help! I do understand the short hand (x?T:F) but I am not sure how you looped through the file twice... Also, can I use <file awk.... instead putting file at the end?
@VictoriaJ. see the updated answer. Quoting the reference, "So, the condition NR == FNR is only true while awk is reading the first file". Regarding your second question, no, you have to use awk '...' file file.
+1 You could avoid calling length() multiple times with a variable and you need to parenthesize the ternary expression for portability: awk '{cur=length($0)} FNR==NR{max=(cur>max?cur:max); next} cur==max' file file.
@EdMorton thank you very much, your {cur=length($0)} makes many sense and code looks cleaner. And also to parenthesize the ternary.
7
$ awk '{cur=length($0); recs[cur] = recs[cur] $0 ORS; max=(cur>max?cur:max)} END{printf "%s", recs[max]}' file
Christina
Christine

If your file's huge and the above has a memory issue, then:

$ awk '{cur=length($0)} cur>max{recs=""; max=cur} cur>=max{recs = recs $0 ORS} END{printf "%s", recs}' file
Christina
Christine

2 Comments

This solution is good in case of a smaller input but since it's storing everything it would not suite for piping large amount of data through it I guess
Yeah, if that really was an issue for the user it'd be trivial to delete recs[] every time max increases or just use a variable instead of an array. I added an alternative for that case.
2

You can use an array to store the (so far) longest line(s)

awk '{if (length($0)==maxlength) {arr[i++]=$0}; if (length($0)>maxlength) {i=0; maxlength=length($0); split("",arr); arr[i++]=$0}}END{for (i in arr) print a[i];}'

Notes:

  • maxlength stores the length of the so far longest lines
  • arr stores the so far longest lines
  • i stores the count of the lines in the array
  • split("",arr) initialises arr as an empty array

This way you don't have to read the file twice, so you can use it in a pipeline as well

Comments

0

You have know about many awk solutions. I would like to also mention that this can be done in perl as well:

perl -lne '$m<($l=length($_))?$m=$l:0;
           push @{$x{$l}},$_;
           END{print "@{$x{$m}}"} ' your_file

Test

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.