Count number of lines after wrapped by terminal’s length [closed]
Asked Answered
T

3

1

Suppose your tput cols (or COLUMNS) is equal to 100 and you have a plain text file foo.txt with a single line that is 120 characters long.

If you wanted to count number of lines it contains you could do cat foo.txt | wc -l and unsurprisingly enough the output would presumably be 1.

But if you’d open the file with a pager, such as less, like less foo.txt then what your eyes would actually see are two lines instead (AFAIK, unless you don’t say --chop-long-lines, less will “wrap" lines that are longer than your terminal’s width).

Again, if you’d try to see line numbers, using less, like less --LINE-NUMBERS foo.txt, than the output would be something like:

1 something something...
1 more stuff

Basically less is “aware” that the only line in foo.txt is longer than your terminal’s width, so it will “wrap” it to visualize, but will tell you that actually first and the second lines that you see are actually the same line #1 in foo.txt.

So, my question is: how could you “calculate” (say, in bash) number of lines after wrapping (number of lines that your eyes see), rather than number of lines that the file actually contains? (In scenario above, the number would be 2 instead of 1.)

Third answered 1/5, 2015 at 22:35 Comment(0)
I
2

Actually, there is a better solution:

fold -w "$COLUMNS" testfile | wc -l

The fold command will wrap a file to a given column count and is widely available as part of the GNU coreutils.

Inboard answered 1/5, 2015 at 23:50 Comment(0)
I
2

This solution will print the number of lines as displayed on the terminal:

#!/bin/bash

seenlines=0
cols=$( tput cols )

# iterate over each line in the file:
while read line
do

    # get length of the line in characters, 
    # subtracting the newline:
    length=$(( $( wc -m <<< "$line" ) - 1 ))

    # add at least one line, and one for each time
    # the line length exceeds the column size of 
    # the terminal, subtracting one character to 
    # avoid the edge case of length==cols:
    seenlines=$( bc <<< "$seenlines + 1 + (${length}-1)/ ${cols}" )
done <testfile

echo "${seenlines} lines seen"
Inboard answered 1/5, 2015 at 22:59 Comment(6)
thanks for quick answer! I was really hoping for a small *NIX command utility that I wasn’t aware of, but your solution will definitely do it. Correct me if I am wrong, but 1 + ${length} / ${cols} will equal to 2 if for a single that is length = cols instead of 1?Third
@exalted: yes, you are right. sorry, it is late here ;-) I've edited my answer to compensate for that and for the fact that wc includes the trailing newline in its count.Inboard
@exalted: I didn't believe it, but there really is that small *NIX command you were looking for, check out the other answer I just added.Inboard
I would still keep this answer around here, just for the records.Third
This what I was looking for. But it has a small bug when $(( (${length}-1) % ${cols} )) -eq 0. In that case an extra line is being deleted. Therefor, you would need to add at the end of the loop: if [[ $(( (${length}-1) % ${cols} )) -eq 0 ]]; then; seenlines=$((seenlines - 1)); fiEarwax
It is also important to remove the non-printable characters from the count: lineOfVisbleCharacters=$(echo "$line" | tr -dc '[[:print:]]')Earwax
I
2

Actually, there is a better solution:

fold -w "$COLUMNS" testfile | wc -l

The fold command will wrap a file to a given column count and is widely available as part of the GNU coreutils.

Inboard answered 1/5, 2015 at 23:50 Comment(0)
I
0

Note: $COLUMNS is built in to bash and returns the current number of columns available for display.

We need to count the number of lines above our $COLUMN limit. We can do this with grep:

expression='.\{'"$COLUMNS"'\}'
echo $expression
.\{80\}
cat foo.txt | grep -c $expression
1

If we add this number to cat foo.txt | wc -l we get the number of lines after wrapping.

Script:

#!/bin/bash
eval $(resize)
expression='.\{'"$COLUMNS"'\}'
echo $expression
raw_lines=`cat foo.txt | wc -l`
big_lines=`cat foo.txt | grep -c "$expression"`
display_lines=`echo "$big_lines + $raw_lines" | bc`
echo "raw lines: $raw_lines"
echo "big lines: $big_lines"
echo "display lines: $display_lines"

Note: line 2 eval $( resize ) is needed to make the $COULMNS variable available from within the script.

Hope this does the trick for you!


Just for kicks, here is how you could find the minimum possible lines after wrapping (assuming no line breaks).

characters="$(cat foo.txt | wc -c)"
minimum_possible_lines_after_wrapping="$(echo $COLUMNS | xargs echo "$characters / " | bc)"
  1. cat the file
  2. count the characters
  3. divide the number of characters by the maximum possible on each line

This only gets us the minimum possible number of lines, however.

Impeachable answered 1/5, 2015 at 23:31 Comment(3)
Thanks for your answer. Although I didn’t try your solution yet, here’s a quick question for you: what if a line is three times $COLUMNS long? If you count just the lines that are longer than $COLUMNS and add this number to total lines fetched by wc -l, you only add +1 for a line that is longer than terminal’s width, but an arbitrary line could be even +2, +3, etc.Third
Great point. This is certainly a shortcoming of the script I posted above. Some sort of loop that iterated through multiples of $COLUMNS and stopped once no lines were found to stretch to that length might be a solution.Impeachable
David, please take a look at https://mcmap.net/q/93491/-count-number-of-lines-after-wrapped-by-terminal-s-length-closed.Third

© 2022 - 2024 — McMap. All rights reserved.