'What's the best way to loop over single line with several separator?

I want to parse the output of fio, I have format them so it has a nice delimiter.

182.07 MB/s|182.55 MB/s|364.62 MB/s|45.5k|45.6k|91.2k#682.65 MB/s|686.24 MB/s|1.36 GB/s|10.7k|10.7k|21.4k#665.21 MB/s|700.56 MB/s|1.36 GB/s|1.3k|1.4k|2.7k#751.97 MB/s|802.05 MB/s|1.55 GB/s|0.7k|0.8k|1.5k

I want to process each string separated with # sign, currently this is what I do.

  • Convert # to \n (newline)

    fio_result=$(printf %s "$fio_result" | tr '#' '\n')
    

    This will output the string like so.

    182.07 MB/s|182.55 MB/s|364.62 MB/s|45.5k|45.6k|91.2k
    682.65 MB/s|686.24 MB/s|1.36 GB/s|10.7k|10.7k|21.4k
    665.21 MB/s|700.56 MB/s|1.36 GB/s|1.3k|1.4k|2.7k
    751.97 MB/s|802.05 MB/s|1.55 GB/s|0.7k|0.8k|1.5k
    
  • Only after that, loop through the variable fio_result.

    echo "$fio_result" | while IFS='|' read -r bla bla...
    

Does anyone have better idea how to achieve what I want ?



Solution 1:[1]

With bash you can do:

#!/bin/bash

fio_result='182.07 MB/s|182.55 MB/s|364.62 MB/s|45.5k|45.6k|91.2k#682.65 MB/s|686.24 MB/s|1.36 GB/s|10.7k|10.7k|21.4k#665.21 MB/s|700.56 MB/s|1.36 GB/s|1.3k|1.4k|2.7k#751.97 MB/s|802.05 MB/s|1.55 GB/s|0.7k|0.8k|1.5k'

while IFS='|' read -d '#' -ra arr
do
    declare -p arr #=> shows what's inside 'arr'
done < <(
    printf '%s' "$fio_result"
)

But, if your need is to format/extract/compute something from fio output then you should switch to an other tool more fit for the job than bash.

Example with awk: calculate the average of the first two columns:

printf '%s' "$fio_result" |
awk -F'|' -v RS='#' '{print ($1+$2)/2}'

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1