I have two variables which contain multiline information and i want to column them.

varA returns

Aug 01
Aug 04
Aug 16
Aug 26

and varB returns

04:25
07:28
03:39
10:06

if i print both variables, it returns

Aug01
Aug04
Aug16
Aug26
04:25
07:28
03:39
10:06

What i want to do is the following:

Aug01 04:25
Aug04 07:28
Aug16 03:39
Aug26 10:06

I'm new in Linux and i would appreciate some advice, thanks.

  • Please include the bash code you used in your attempt to print the two variable. It is so that we can see what you have done wrong in your attempt. – Bernard Wei Aug 17 at 22:17

Meet paste, part of the preinstalled GNU core utilities:

$ paste <(printf %s "$varA") <(printf %s "$varB")
Aug 01  04:25
Aug 04  07:28
Aug 16  03:39
Aug 26  10:06

paste takes files and not variables as input, so I used bash Process Substitution and just printed the variable content with printf. The default delimiter between columns is TAB, you can change that with the -d option, e.g. paste -d" " for a single space character. To learn more about paste have a look at the online manual or run info '(coreutils) paste invocation'.

  • @dessert It worked!! thank you so much! – BNairb Aug 20 at 2:05
  • 1
    @BNairb If this answer solved your issue, please take a moment and accept it by clicking on the check mark to the left. That will mark the question as answered and is the way thanks are expressed on the Stack Exchange sites. – dessert Aug 21 at 6:38

If you just want to simply display the text variables side by side, @dessert has the most simple (best?) solution using print. However if you want to be able to manipulate each piece individually, you could easily convert the vars to arrays instead, and loop through that.

#!/bin/bash

# declare the multi-line variables
var1="1
2
3
4"
var2="a
b
c
d"

# backup internal field separator to be safe
IFSave=$IFS

# set IFS to newline so vars will use newline to split into array
IFS=$'\n'

# split variables into array
foo=($var1)
bar=($var2)

#restore IFS to original value to be safe
IFS=$IFSave

# loop array foo, and cross reference key in array bar
for i in "${!foo[@]}"; do 
  printf "${foo[$i]} : ${bar[$i]}\n"
done

# you can allso now print single corresponding lines:
line=3

let id=$line-1 # arrays start at 0, so need to remove one

printf "\nPrinting line number $line\n"
printf "${foo[$id]} : ${bar[$id]}\n"

If you wanted to avoid external utilities and do it natively in the shell, you could use read with separate file descriptors / here strings for each variable:

while IFS= read -r -u3 a && read -r -u4 b; do 
  printf '%s\t%s\n' "$a" "$b"
done 3<<<"$varA" 4<<<"$varB"
Aug 01  04:25
Aug 04  07:28
Aug 16  03:39
Aug 26  10:06

Although it's often considered bad practice to use the shell for text processing, it might be excused in the case that you already have the data in shell variables.

You can do this with the POSIX tool pr:

varA='Aug 01
Aug 04
Aug 16
Aug 26'
varB='04:25
07:28
03:39
10:06'
pr -2 -t <<eof
$varA
$varB
eof

Result:

Aug 01                              04:25
Aug 04                              07:28
Aug 16                              03:39
Aug 26                              10:06

Or for single tab:

pr -2 -t -s

Or for single space:

pr -2 -t -s' '

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pr.html

Or with column from the util-linux package:

column -c 20 <<eof
$varA
$varB
eof

paste used with column provides clean output. For convenience of most users I'll use an example of directories already on their system.

$ cd /sys/devices/system/cpu/cpu0/cpufreq

$ ls
affected_cpus                             energy_performance_preference  scaling_governor
cpuinfo_max_freq                          related_cpus                   scaling_max_freq
cpuinfo_min_freq                          scaling_available_governors    scaling_min_freq
cpuinfo_transition_latency                scaling_cur_freq               scaling_setspeed
energy_performance_available_preferences  scaling_driver

$ cat *
0
3500000
800000
4294967295
default performance balance_performance balance_power power 
balance_performance
0
performance powersave
875982
intel_pstate
powersave
3500000
800000
<unsupported>

$ paste <(ls *) <(cat *) | column -s $'\t' -t
affected_cpus                             0
cpuinfo_max_freq                          3500000
cpuinfo_min_freq                          800000
cpuinfo_transition_latency                4294967295
energy_performance_available_preferences  default performance balance_performance balance_power power 
energy_performance_preference             balance_performance
related_cpus                              0
scaling_available_governors               performance powersave
scaling_cur_freq                          1079503
scaling_driver                            intel_pstate
scaling_governor                          powersave
scaling_max_freq                          3500000
scaling_min_freq                          800000
scaling_setspeed                          <unsupported>

Without the column command, the fields in the second column are unaligned, making it more difficult to read.

$ paste <(ls *) <(cat *)
affected_cpus   0
cpuinfo_max_freq    3500000
cpuinfo_min_freq    800000
cpuinfo_transition_latency  4294967295
energy_performance_available_preferences    default performance balance_performance balance_power power 
energy_performance_preference   balance_performance
related_cpus    0
scaling_available_governors performance powersave
scaling_cur_freq    1943068
scaling_driver  intel_pstate
scaling_governor    powersave
scaling_max_freq    3500000
scaling_min_freq    800000
scaling_setspeed    <unsupported>

For more column command examples see this article: Viewing Linux output in columns

If the column command is not already installed use:

sudo apt update
sudo apt install util-linux

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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