14

I'd like to find lines in my code which exceed a certain length. My code is in multiple files. What's a good way to do this?

I'd like to know the files and line numbers; content would be preferred, but not necessary. The purpose of the exercise is to then figure out how to break the lines (probably manually).

2
  • How do you want the results? As the lines itself (their content, as in grep), or as line numbers, or as something else (perhaps you want to apply another action on them)? Probably the most convenietn way to do this depends on what will be done with these lines next. Mar 27, 2014 at 15:21
  • @imz--IvanZakharyaschev Good point. Question updated.
    – Marcin
    Mar 27, 2014 at 16:01

7 Answers 7

14

With grep:

grep -En '.{12}' file

For lines at least 12 characters long.

With several files:

find . -type f -exec grep -En '.{12}' {} +

Some grep implementations like GNU grep, can do the file-finding themselves.

grep -rEn '.{12}' .

But beware of symlinks and other non-regular files.

1
  • I like this because it's simple, and I was hoping to do something like this (still haven't gotten around to it).
    – Marcin
    Mar 28, 2014 at 15:49
12

AWK solution

awk '{       
if (length($0) > 5)
        print $0;'} yourfile

Or, more concisely:

awk 'length > 5' file
6
  • 9
    We can shorten your version awk 'length > 5'
    – cuonglm
    Mar 27, 2014 at 15:15
  • Gnouc is a brace killer ;)
    – Ouki
    Mar 27, 2014 at 15:16
  • 3
    With GNU awk the somewhat less elegant but concise awk '/^.{6,}/'
    – iruvar
    Mar 27, 2014 at 15:56
  • Your first example has one mistake single quotes should be after end of close brace. Mar 27, 2014 at 16:06
  • 3
    @1_CR, That's POSIX and can be shortened to awk '/.{6}/' (actually GNU awk until recently used to be the one where that wouldn't work unless you pass POSIXLY_CORRECT to its environment). Mar 27, 2014 at 16:20
6

Bash solution

#!/bin/bash

count=0

while read; do
    ((++count)) 
    len=${#REPLY}
    if ((len > 80)); then
        echo "Line $count is $len characters."
    fi
done

So, e.g., ./whatever.sh < input.file. This does not include the newline by subtracting 1 from $len; if that's not desirable, or your input uses CRLF endings, you should adjust accordingly.

11
  • 1
    why not ${#line} to avoid the expr fork?
    – iruvar
    Mar 27, 2014 at 15:36
  • 1
    ha ha, +1 for the pure bash solution. But please note that unless you stick in IFS= in front of read, leading spaces will be ignored.
    – iruvar
    Mar 27, 2014 at 15:43
  • 1
    Added in a few bash good practices. Also please note the the newline is not taken into $line so no need to subtract one.
    – iruvar
    Mar 27, 2014 at 17:40
  • 2
    @1_CR actually if you don't give read a name to read into, it will read into REPLY and include all whitespace. No IFS setting needed.
    – kojiro
    Mar 27, 2014 at 18:37
  • 2
    That's going to be extremely slow and handles the backslash characters specially. while read loops to process text are really bad practice. Mar 27, 2014 at 20:32
5

Since the one thing that was missing was a sed solution

sed -n '/^.\{6,\}/p' file
4

With perl (for instance), assuming you are searching for lines longer than 80 characters:

To display the lines:

$ perl -nle 'print if length > 80' your_file

To display the lines number:

$ perl -nle 'print "$.\n" if length > 80' your_file

Or both:

$ perl -nle 'print "[$.]:  $_\n" if length > 80' your_file
1
  • 3
    You should add -l command line, perl will count line break in your lines.
    – cuonglm
    Mar 27, 2014 at 15:22
1

Ruby :

ruby -lne 'puts $_ if $_.size > 5' intputfile

Python :

python -c "import sys;[ sys.stdout.write(''.join(line)) for line in sys.stdin if len(line.strip()) > 5 ]" < inputfile
1

Here's another bash solution (bash 4):

minlen=5 # minimum length of a line
mapfile -tO1 < inputfile # Map the file to the array MAPFILE (by default)
                         # Start the array at index 1
for i in "${!MAPFILE[@]}"; do
  (( ${#MAPFILE[i]} > minlen )) || unset MAPFILE[i] # Remove shorter elements
done

The resulting array is sparse, so the array indices are maintained. Since we started at 1, the indices are the line numbers of the lines we kept. We can output just those line numbers:

printf 'Long lines found at: '
printf '%d, ' "${!MAPFILE[@]}"
echo

Or we can output the lines themselves:

printf '%s\n' "${MAPFILE[@]}"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .