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)"
1
  • 1
    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, 2012 at 12:13

5 Answers 5

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.

0
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
3
  • 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, 2016 at 16:03
  • I think there are some typos in the script because it doesn't work. Is it perhaps a missing double quote "? Jan 16, 2021 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 4, 2021 at 14:30
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 
2
  • 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, 2012 at 17:22
  • You need to quote all of your expansions, or this will easily break.
    – Chris Down
    Dec 23, 2012 at 20:17
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$
0
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.

You must log in to answer this question.

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