1

I've been googling but I can't find any scripts that uses the while loop to read the lines. I'm stuck and I'm not sure on where to start

Heres the question: Write a bash script longestline.sh that use a while read loop to read lines of text from its standard input . the script should keep track of the longest line that it has read so far, and when it reaches the end of the input, print that line.

Also, I'm not sure if the question asks me to input a file with lines of text and it will read it off that or input the lines of text myself .

Thanks, KB

3 Answers3

1

As per cuonglm's link, loops in bash are to be avoided.

In that spirit, the code below gets the length of the longest line in a file using awk, a standard unix tool, but without bash loops:

awk '{n=length($0)>n?length($0):n} END{print n}' file

If you want to print the longest line, instead of getting its length, then use:

awk '{longest=length($0)>length(longest)?$0:longest} END{print longest}' 
John1024
  • 74,655
0

I haven't written bash in a long while, so I'll accept any type of criticism :) My solution would be something like this:

n=0
longest=""
while read line; do
    len=`echo $line | wc -m`
    if [ $len -ge $n ]; then
        n=$len
        longest=$line
    fi
done 

echo $longest

I read @cuonglm's suggestion, but I couldn't think of a way to do this using less process invocations. I'm open to suggestions, of course.

Regarding your last question, it really doesn't matter. This script would work with you entering the lines, or with a file being used as input.

  • How about len=${#line}? – steeldriver Feb 13 '15 at 13:03
  • To get the whole line (e.g. including whitespace) you have to write while IFS= read -r line; do . And it's expensive; the subshell and external wc is unnecessary (see steeldrivers suggestion). – Janis Mar 03 '15 at 12:58
0

You can get a list of all line numbers one per line ordered first by length and second by line number starting w/ the largest like...

</path/to/infile LC_ALL=C \
tr -c \\n 1|grep -n '.\|'|sort -t: -rnk2

The method is very simple - tr converts every input byte which is not a \newline character to a 1, grep -n prepends each line's number then a : to all lines in its input, which sort then sorts in reverse numeric order from the 2cd field through the tail of the line as delimited by a :. So the longest string of 1s floats to the top.

You should beware, though, that if the input includes multibyte characters then this will number only by byte - not by character. To do the latter thing robustly is not a minor undertaking (as I understand it).

In any case - in an ASCII locale - the above should be very fast even for very large inputs. And it requires very little else to be a complete solution:

f=/path/to/file
n=$(<"$f" tr -c \\n 1|grep -n '.\|'|sort -t: -rnk2|head -n1)
l=$(<"$f" head -n"${n%:*}"|tail -n1)
printf "Line #%s at #${#l} bytes. Its contents:\n%s\n" \
   "${n%:*} is (possibly tied-for) the longest in $f" "$l"
mikeserv
  • 58,310