Home > Net >  Bash - Combine output from two commands
Bash - Combine output from two commands

Time:01-17

I'm trying to add the output of a command to the output of another command.

Output of first command:

-changing number of heading lines -
| Interface | Hostname | Speed  |
|   dl29    |  host1   | 10Gbit |
|   dl27    |  host2   | 10Gbit |
-end of output-

Output of second command:

dl27=Time: 1day 30min 3sec
dl29=Time: 5min 55sec

Combined result should be:

-heading lines-
| Interface | Hostname | Speed  |
|   dl29    |  host1   | 10Gbit | Time: 5min 55sec
|   dl27    |  host2   | 10Gbit | Time: 1day 30min 3sec

Does anyone have an idea how to accomplish this?

CodePudding user response:

Given these two 'commands' in bash:

cmd_1(){
    echo '| Interface | Hostname | Speed  |
|   dl29    |  host1   | 10Gbit |
|   dl27    |  host2   | 10Gbit |'
}

cmd_2(){
    echo 'dl27=Time: 1day 30min 3sec
dl29=Time: 5min 55sec'
}

You can redirect the commands into awk to get what you are looking for:

awk 'BEGIN{FS="\\|[[:blank:]]*|[[:blank:]]*\\|"}

FNR==NR{
    lines[FNR]=$0
    idx[$2]=FNR
    next
}
FNR==1{
    print lines[1]}
{
    split($0,a,"=")
    print lines[idx[a[1]]], a[2]
}
' <(cmd_1) <(cmd_2)

Prints:

| Interface | Hostname | Speed  |
|   dl27    |  host2   | 10Gbit | Time: 1day 30min 3sec
|   dl29    |  host1   | 10Gbit | Time: 5min 55sec

CodePudding user response:

gawk -F'\\s*[=|]\\s*' 'NR == FNR { a[$1] = $2; next }
        $2 in a { $0 = $0 " " a[$2] } 1' <(cmd1) <(cmd2)

Replace \\s with [^[:space:]] or [^ ] if your non-GNU-yet-still-using-bash system doesn't support it.

Gawk of course implies GNU Awk if that isn't obvious enough.

CodePudding user response:

Assumptions:

  • each line of the 2nd set of output has a single =
  • every data line from the 1st set of output has a matching line in the 2nd set of output
  • final output lines should be in the same order as they appear in the 2nd set of output (ie, no need to sort any of the data lines)

Modifying dawg's functions to match OP's latest update:

cmd_1(){
    echo '-changing number of heading lines -
| Interface | Hostname | Speed  |
|   dl29    |  host1   | 10Gbit |
|   dl27    |  host2   | 10Gbit |
-end of output-'
}

cmd_2(){
    echo 'dl27=Time: 1day 30min 3sec
dl29=Time: 5min 55sec'
}

One awk idea:

awk '
FNR==NR       { split($0,arr,"=")
                timings[arr[1]]=arr[2]
                next
              }
FNR==1        { print "-heading lines-"; next }
FNR==2        { print                  ; next }
$2 in timings { print $0,timings[$2] }
' <(cmd_2) <(cmd_1)

This generates:

-heading lines-
| Interface | Hostname | Speed  |
|   dl29    |  host1   | 10Gbit | Time: 5min 55sec
|   dl27    |  host2   | 10Gbit | Time: 1day 30min 3sec

CodePudding user response:

$ awk '
    NR == FNR { time[$1]=$2; next }
    { print $0 ($2 in time ? " " time[$2] : "") }
' FS='=' <(cat cmd2out) FS=' *[|] *' <(cat cmd1out)
-changing number of heading lines -
| Interface | Hostname | Speed  |
|   dl29    |  host1   | 10Gbit | Time: 5min 55sec
|   dl27    |  host2   | 10Gbit | Time: 1day 30min 3sec
-end of output-

Replace cat cmd1out and cat cmd2out with your actual commands. Note the order in which they must be called, command 2 first.

  •  Tags:  
  • Related