user1669844
user1669844

Reputation: 763

How to redirect output in multiple columns in bash?

I am running a test multiple times on terminal and redirecting output to a file. While redirecting I want each run as a separate column. Currently, I am able to get the following:

Run1
1
2
3
4
Run2
1
2
3
4

How to redirect it as follow:

Run1  Run2
1      1
2      2
3      3
4      4

Upvotes: 9

Views: 5477

Answers (3)

J C Gonzalez
J C Gonzalez

Reputation: 911

While the accepted solution with pr is quite elegant, it has a problem, similar to the one with paste: if the length of the different lines are bigger than 8 (the default size in spaces of a tab char), the output lines are displaced. The bigger the difference in length of the lines, the messier gets the output.

Unfortunately, I did not find a more robust way to do this than using a small awk script, that of course can be put in a separate file for reuse.

If you have a file like this (lipsum.txt):

$ cat lipsum.txt
Lorem ipsum dolor sit amet, 
consectetur adipiscing elit. 
Cras hendrerit scelerisque sollicitudin. 
In at mauris cursus, 
varius eros ut, 
dignissim urna. 
Nullam est orci, 
molestie sit amet risus in, 
commodo dignissim justo. 
Morbi eu enim leo. 
Proin pulvinar consectetur elit, 
in viverra nisl ultrices quis. 
Vivamus ac lacus eget urna auctor finibus. 
Suspendisse potenti. 
Vestibulum sed ligula nisl.

The accepted solution will result as follows:

$ cat lipsum.txt | pr -2 -t -s
Lorem ipsum dolor sit amet,     commodo dignissim justo.
consectetur adipiscing elit.    Morbi eu enim leo.
Cras hendrerit scelerisque sollicitudin.    Proin pulvinar consectetur elit,
In at mauris cursus,    in viverra nisl ultrices quis.
varius eros ut,     Vivamus ac lacus eget urna auctor finibus.
dignissim urna.     Suspendisse potenti.
Nullam est orci,    Vestibulum sed ligula nisl.
molestie sit amet risus in,     

With the following (long) oneliner, you save in an array all the lines while measuring their length, and then shows them again in two columns, with the appropriate width (set to the max. length of the lines).

$ cat lipsum.txt |awk 'BEGIN{w=0;}{lines[NR]=$0;l=length($0);w=l>w?l:w;}END{wd=W>0?W:w;h=rshift(NR,1)+(NR%2);for (i=1;i<=h;i++){printf "%*s %s %*s\n",-wd,lines[i],sep,-wd,lines[i+h];}}'
Lorem ipsum dolor sit amet,                  commodo dignissim justo.                   
consectetur adipiscing elit.                 Morbi eu enim leo.                         
Cras hendrerit scelerisque sollicitudin.     Proin pulvinar consectetur elit,           
In at mauris cursus,                         in viverra nisl ultrices quis.             
varius eros ut,                              Vivamus ac lacus eget urna auctor finibus. 
dignissim urna.                              Suspendisse potenti.                       
Nullam est orci,                             Vestibulum sed ligula nisl.                
molestie sit amet risus in,       

You can even set the string separator with the variable sep and the width of the column with the variable W (if it is smaller than the max. line length, you will get effects similar to those with paste or pr, of course):

$ cat lipsum.txt |awk -v W=50 -v sep='|:|' 'BEGIN{w=0;}{lines[NR]=$0;l=length($0);w=l>w?l:w;}END{wd=W>0?W:w;h=rshift(NR,1)+(NR%2);for (i=1;i<=h;i++){printf "%*s %s %*s\n",-wd,lines[i],sep,-wd,lines[i+h];}}'
Lorem ipsum dolor sit amet,                        |:| commodo dignissim justo.                          
consectetur adipiscing elit.                       |:| Morbi eu enim leo.                                
Cras hendrerit scelerisque sollicitudin.           |:| Proin pulvinar consectetur elit,                  
In at mauris cursus,                               |:| in viverra nisl ultrices quis.                    
varius eros ut,                                    |:| Vivamus ac lacus eget urna auctor finibus.        
dignissim urna.                                    |:| Suspendisse potenti.                              
Nullam est orci,                                   |:| Vestibulum sed ligula nisl.                       
molestie sit amet risus in,                        |:|      

Upvotes: 0

Rub
Rub

Reputation: 2738

If command1 produces Run1 and command2 produces Run2

paste <(command1) <(command2) | column -s $'\t' -tne

will join the outputs into columns.

Here is an example with silly commands

# paste <(ls -1 /var/log/*log) <(ls -1 /var/log/*/*_log) | column -s $'\t' -tne
/var/log/alternatives.log  /var/log/cups/access_log
/var/log/auth.log          /var/log/cups/error_log
/var/log/boot.log          /var/log/cups/page_log
/var/log/bootstrap.log     
/var/log/daemon.log        
/var/log/dpkg.log          
/var/log/faillog           
/var/log/fontconfig.log    
/var/log/kern.log          
/var/log/lastlog           
/var/log/pm-powersave.log  
/var/log/pm-suspend.log    
/var/log/pycentral.log     
/var/log/syslog            
/var/log/user.log          
/var/log/vbox-install.log  
/var/log/wvdialconf.log    
/var/log/Xorg.0.log        
/var/log/Xorg.1.log        
/var/log/Xorg.2.log  

Reference: https://sleeplessbeastie.eu/2018/11/19/how-to-display-output-of-multiple-commands-using-columns/

IF you want to display AND redirect to a file, each command could include a tee that does that.

It is always good idea to include your own commands (or dummy ones) so we can give you a more specific answer.

Upvotes: 0

Cyrus
Cyrus

Reputation: 88776

With pr:

pr -2 -t -s file

or from stdin:

cat file | pr -2 -t -s

Output:

Run1    Run2
1       1
2       2
3       3
4       4

See: man pr

Upvotes: 11

Related Questions