39
MYPATH=/var/www/html/error_logs/
TOTALFILE=$(ls $MYPATH* | wc -l)
FILETIME=$(stat --format=%y $MYPATH* | head -5 | cut -d'.' -f1)  
FILE=$(ls -1tcr $MYPATH* | head -5 | rev | cut -d/ -f1 | rev)
TOPLINE=$(head -1 $MYPATH* | grep -Po '".*?"' | head -5)

How can I elegantly print these 5 files of information into columns with headers?

FILE CREATED TIME   | FILE NAME        | ERROR HEADER
---------------------------------------------
$FILETIME           | $FILE            | $TOPLINE
2012-11-29 11:27:45 | 684939947465     | "SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)"

and so on with all 5 files.

total files: $TOTALFILE

is there any easy way to get what I want?

This is the output I get when I echo every variable:

2012-11-29 11:27:45 2012-11-29 11:27:41 2012-11-28 23:33:01 2012-11-26 10:23:37 2012-11-19 22:49:36
684939947465 1313307654813 1311411049509 1234980770182 354797376843
"SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)" "SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)" "Connection to localhost:6379 failed: Connection refused (111)" "An error occurred connecting to Redis." "SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)"
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
ADM
  • 501
  • 1
  • 4
  • 7
  • You got three answers to your question, which all address the things you ask. You should be much more precise in what you want to get a specific answer. – Bernhard Dec 24 '12 at 12:13

5 Answers5

43

I would recommend using printf, e.g.:

printf "%-30s | %-30s | %-30s" "$FILETIME" "$FILE" "$TOPLINE"

Where %-30s means to reserve 30 characters for the input argument of type string. The - denotes left alignment.

Cristian Ciupitu
  • 2,430
  • 1
  • 22
  • 29
Bernhard
  • 11,992
  • 4
  • 59
  • 69
33

You can use the column command which on Linux is part of the util-linux package. It's also available on FreeBSD, NetBSD, OpenBSD and DragonFly BSD.

Combine this with a loop and you're in business, e.g.:

#!/bin/sh

MYPATH=/
TOTALFILE=$(ls $MYPATH/* | wc -l)
FILE=$(ls -1tcr $MYPATH/* | head -5 | rev | cut -d/ -f1 | rev)

declare -a FILES
declare -a FILETIME

OUTPUT="FILENAME CREATED TIME ERROR_HEADER\n\n------------------------------ ----------------------------- ----------------------------------- ------$"

for i in $MYPATH/*;
do
    FILES[${#FILES[@]}]="$i"
    FILETIME[${#FILETIME[@]}]=$(stat --format=%y $i | head -5 | cut -d'.' -f1)
    TOPLINE=$(head -1 $i | grep -Po '".*?"' | head -5)

    OUTPUT="$OUTPUT\n${FILES[${#FILES[@]}-1]} ${FILETIME[${#FILETIME[@]}-1]} $TOPLINE\n"
done

echo -ne $OUTPUT | column -t
QNimbus
  • 446
  • 3
  • 4
  • I needed further control of what went in which column, so I split columns on '*' and used something like `sed 's/^/ \* \*/g'` for shifting things from first column into third. Worked a treat for me. – LOAS Nov 16 '16 at 16:03
  • I think there are some typos in the script because it doesn't work. Is it perhaps a missing double quote `"`? – Cristian Ciupitu Jan 16 '21 at 17:15
  • this answer does it after you have gone through the loop (which may take some time). I think that the prinf answer from Bernhard is better as it does it on the fly and so is indefinitely scaleable, as you can flush the output to the console in realtime. – Banoona Oct 04 '21 at 14:30
3

Not sure if this is what are you up to, "paste" in unix can arrange files in column, you may need printf to reformat the sttdout. example:

bash-3.2$ cat A
agc
wkwk
slsl
bash-3.2$
bash-3.2$ cat B
123
5757
sier
bash-3.2$ paste A B
agc     123
wkwk    5757
slsl    sier
bash-3.2$
mwfearnley
  • 1,104
  • 1
  • 16
  • 19
Them Huyen
  • 39
  • 2
3

I would go with a a loop

printf " %-20s | %-20s | %-20s\n " FILE\ CREATED\ TIME FILE\ NAME ERROR\ HEAD
for i in "$MYPATH"/*
do
    printf "%-20s | %-20s | %-20s\n " $FILENAME $FILE $TOPLINE
done
printf "Total Files: %s" $TOTALFILES 
jordanm
  • 41,988
  • 9
  • 116
  • 113
BitsOfNix
  • 5,057
  • 2
  • 25
  • 34
  • I gave you the how not the solution. Now you need to adapt your code so that the FILENAME FILE and TOPLINE are taken care inside of the loop instead of doing it before the loop. – BitsOfNix Dec 23 '12 at 17:22
  • You need to quote all of your expansions, or this will easily break. – Chris Down Dec 23 '12 at 20:17
2

@qnimbus answer is probably best for Linux systems but on Sun or IBM (if you're un/lucky enough to be using one in 2019) this command may not be available. Instead you could use the pr command to get the same effect. From the examples on the linked page you can use the following:

pr -3 word.lst | qprt

to print the file word.lst in 3 columns. That said, this is only a part of a solution to your problem and for the rest I defer to @qnimbus answer.

nonsensickle
  • 121
  • 3