2

Say I want to search for "ERROR" within a bunch of log files.

I want to print one line for every file that contains "ERROR".

In each line, I want to print the log file path on the left-most edge while the number of "ERROR" on the right-most edge.

I tried using:

printf "%-50s %d" $filePath $errorNumber

...but it's not perfect, since the black console can vary greatly, and the file path sometimes can be quite long.

Just for the pleasure of the eyes, but I am simply incapable of doing so. Can anyone help me to solve this problem?

agc
  • 7,973
  • 2
  • 29
  • 50
user3151209
  • 73
  • 1
  • 12
  • What have you tried and what is sample output? – anubhava Apr 27 '17 at 17:41
  • Suppose your terminal in N characters wide. How do you want to print a line that contains 10N characters? – William Pursell Apr 27 '17 at 17:50
  • I tried using (printf "%50s %d", $filePath, $errorNumber), but it's not perfect, since the black console can vary greatly, and the file path sometime can be quite long. I don't have any sample, simply having the desire to do so. Is it hard to imagine? It's like having a table of two cells, one is left-aligned, the other one is right-aligned . – user3151209 Apr 27 '17 at 17:58
  • @WilliamPursell even if the line is longer than the terminal's width, it is still one line, can be shown in multiple rows. – user3151209 Apr 27 '17 at 18:03
  • Yes, but do you want your error count to appear at the right edge of the first line, at the right edge of the last line, or at the right edge of all lines? Do you want the filenames to be aligned (IOW, does `grep -H` satisfy the first requirement?) Are you looking to pre-count all the errors and buffer the output (so that the first line that matches in the file will be printed with an error count of the entire file?). You need to provide some sample input and sample output. What you want is certainly possible, but it's unclear exactly what you want. – William Pursell Apr 27 '17 at 18:27
  • @WilliamPursell yes, you are right, it did confuse sometimes. – user3151209 Apr 29 '17 at 10:37

1 Answers1

5

Using bash and printf:

printf "%-$(( COLUMNS - ${#errorNumber} ))s%s" \
       "$filePath" "$errorNumber"

How it works:

  1. $COLUMNS is the shell's terminal width.

  2. printf does left alignment by putting a - after the %. So printf "%-25s%s\n" foo bar prints "foo", then 22 spaces, then "bar".

  3. bash uses the # as a parameter length variable prefix, so if x=foo, then ${#x} is 3.


Fancy version, suppose the two variables are longer than will fit in one column; if so print them on as many lines as are needed:

printf "%-$(( COLUMNS * ( 1 + ( ${#filePath} + ${#errorNumber} ) / COLUMNS ) \
          - ${#errorNumber} ))s%s"   "$filePath" "$errorNumber"

Generalized to a function. Syntax is printfLR foo bar, or printfLR < file:

printfLR() { if [ "$1" ] ; then echo "$@" ; else cat ; fi |
             while read l r ; do
                 printf "%-$(( ( 1 + ( ${#l} + ${#r} ) / COLUMNS ) \
                              * COLUMNS - ${#r} ))s%s"   "$l" "$r"
             done ;  }

Test with:

# command line args
printfLR foo bar
# stdin
fortune | tr -s ' \t' '\n\n' | paste - - | printfLR
agc
  • 7,973
  • 2
  • 29
  • 50
  • That's great, the COLUMNS! How do you know this. It's working in plan printf statement, but what if I want to use it with awk ,like awk 'printf "%-$(( COLUMNS ...some calculations...))s" $1', and inside a script? The COLUMNS will be 0, and printf of awk can not translate the COLUMN. Tried the whole morning, can't get it working with awk. – user3151209 Apr 28 '17 at 05:28
  • @user3151209, For shell variables with `awk`, see [Jotne's answer](http://stackoverflow.com/a/19075707/6136214) to [How to use shell variables in an awk script](http://stackoverflow.com/questions/19075671/how-to-use-shell-variables-in-an-awk-script). – agc Apr 28 '17 at 14:37
  • @user3151209, `$COLUMNS` and `$LINES` are standard [*POSIX shell* variables](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html). – agc Apr 28 '17 at 14:46
  • 1
    Great answer. Just a note: the *format* of `LINES` and `COLUMNS` is specified, but POSIX doesn't guarantee that these variables *exist*. Bash sets these automatically when we enable the `checkwinsize` option. If our system doesn't do this for us (like Cygwin), we can enable the option by adding `shopt -s checkwinsize` to *.bashrc*. [More info here.](https://stackoverflow.com/a/48016366/5209322). – Cy Rossignol Jan 03 '18 at 16:57