7

How to cut off lines that are longer than some width, and marking the lines that were chopped off with an ellipsis?

Only lines that were actually shortened should be marked, but not lines that had just the right lenght in the first place.

I would like to use the command in a pipeline.

  • Do you want to use the three characters ... or the single character ? – Mark Plotnick Sep 14 '14 at 12:17
  • Good point; For this question, let's use the three ".", like "...", as this may be more difficult than one ellipsis character. – Volker Siegel Sep 14 '14 at 12:19
13

This will truncate the string, chop off an additional three characters, and add "..." if the length is longer than the value you supply as a parameter.

other_programs | \
awk -v len=40 '{ if (length($0) > len) print substr($0, 1, len-3) "..."; else print; }'
|improve this answer|||||
  • That's good, it makes the lines with ellipsis as long as the longest lines! And handles the calculation of the length too. – Volker Siegel Sep 14 '14 at 13:20
7

Try this:

awk -F '' '{if (NF > 70) {print substr($0, 0, 71)"..."} else print $0}'

If NF is too high, the simpler way:

awk '{if (length($0) > 70) {print substr($0, 0, 71)"..."} else print $0}'

or a shorter version:

awk 'length > 70{$0=substr($0,0,71)"..."}1'
|improve this answer|||||
  • Sorry about that quote. Copy-pasta selection mistake. – muru Sep 14 '14 at 11:26
  • 3
    This will cause error in some implements of awk, if length greater than max NF. Example, mawk has max NF 32767. – cuonglm Sep 14 '14 at 11:38
  • Whoever added the third version, it doesn't have ellipsis. – muru Sep 14 '14 at 15:25
  • 1
    Sorry, miss typo, updated. – cuonglm Sep 14 '14 at 15:27
  • @Gnouc thanks for the shorter command. I'm not very sure of awk shortcuts, so I usually default to longer versions. :) – muru Sep 16 '14 at 23:15
5

Some possibilities:

  • with sed

    sed -E 's/(.{N})(.{1,})$/\1.../' file
    
  • slightly more elegantly with perl (using lookbehind)

    perl -pe 's/(?<=.{N}).{1,}$/.../' file
    

where N is the number of characters after which you wish to replace with the ellipsis.

|improve this answer|||||
  • -E is meant to be -e, I assume? man sed does not know -E – phil294 Sep 1 '17 at 0:02
  • @Blauhirn -E stands for Extended Regular Expression - it's the POSIX equivalent of the GNU sed -r or --regex-extended flag. It's mentioned in the info page I think (info sed then navigate to Invoking sed -- Command-Line Options) – steeldriver Sep 1 '17 at 1:37
3

awk, sed, and perl, as presented in the other answers, excel at text processing and are probably the best tools for the job.

But you can also do this in pure bash (i.e., "without leaving the shell"), if you like:

n=70
while read -r; do
    if ((${#REPLY}<=n))
        then printf '%s\n' "$REPLY"
        else printf '%s...\n' "${REPLY:0:$((n-3))}"
    fi
done < filename

Replace 70 with the maximum desired length, and filename with the input file.

To use this on the right side of a pipe (i.e., to pipe another command's output to it), remove < filename and either set n beforehand or enclose the whole thing in { ... ;}:

{ n=70
while read -r; do
    if ((${#REPLY}<=n))
        then printf '%s\n' "$REPLY"
        else printf '%s...\n' "${REPLY:0:$((n-3))}"
    fi
done ;}

(This bracket-enclosed version also works fine in other contexts, including with redirection as above. The brackets are unnecessary in that use case, but not harmful.)

This looks like:

ek@Ilex:~$ help read | head -5 | { n=70
> while read -r; do
>     if ((${#REPLY}<=n))
>         then printf '%s\n' "$REPLY"
>         else printf '%s...\n' "${REPLY:0:$((n-3))}"
>     fi
> done ;}
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N n...
    Read a line from the standard input and split it into fields.

    Reads a single line from the standard input, or from file descr...
    if the -u option is supplied.  The line is split into fields as...

Note that, in common with the other solutions that have been presented so far, this will fail to perfectly limit output width in the presence of characters that display more than one column wide, such as horizontal tabs.

|improve this answer|||||
0

Another perl solution:

perl -ple '$_ = sprintf "%.70s...", $_ if length > 70' file
|improve this answer|||||
0

The accepted answer written as a function with example, also putting the ... in the middle of the string rather than the end:

truncate() {    
    echo "$@" | \
    awk -v len=15 '{ if (length($0) > len) print substr($0, 1, len-3) "..." substr($0, length($0) - len, length($0)); else print; }'
}

example:

parse_branch() {
    branch=$(git symbolic-ref --short HEAD || hg branch)
    truncate "$branch"
}
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.