Bash: 从循环流中捕获 stdError

Bash: capture stdError from looped stream

我有一个 cpp 可执行文件 (mycat),它连续从共享内存中读取循环音频流,并将数据通过管道传输到 stdOut,将元数据信息传输到 stdErr。 mycat 为音频流的每个条目输出 12 行,包含元数据信息,如下所示:

0x1 (TimeStamp) 12Bytes:2956 +     6793/(47999+1) (0.141521) delta= 0+    1536/(47999+1) (0.032000) 2956.151418 -9.898ms 2016.04.04 16:06:37.700
0x4 (ReferenceTime) 12Bytes:2956 +  6156972/(26999999+1) (0.228036) delta= 0+ 1618519/(26999999+1) (0.059944) 2956.151426 76.610ms 2016.04.04 16:06:37.700
0x6 (ProcessDelay) 4Bytes: 64 (0x40)
0x7 (ClockAccuracy) 8Bytes: offset=0.000ppm (+-0.000ppm)
0xb (ClockId) 8Bytes: 01 00 00 00 42 22 01 00
0x20001 (SampleRate) 4Bytes: 48000 (0xbb80)
0x20002 (Channels) 4Bytes: 6 (0x6)
0x20003 (PcmLevel) 24Bytes: -21307 -20348 -31737 -42427 -28786 -26525
0x20004 (PcmPeak) 24Bytes: -14366 -13360 -25203 -39427 -19067 -21307
0x2000e (DolbyDpMetadata) 39352Bytes:
Linear Time: 2956 +     6793/(47999+1) (0.141521) delta= 0+    1536/(47999+1) (0.032000)
2016.04.04 16:06:37.700 update: slot=0xe2840 validTo=0x3d1dd180 shmT=0x3d195200 (delta=294784) doffset=0xec2c0 msize=39552 dsize=18432 type=0x20001 (PCMS16) data bytes: df f4 f2 fc

我想要的是一个 bash 脚本:

1) 启动 mycat 例如。 ./mycat shm_name > /dev/null.

2) 从 mycat 读取 stdErr 直到第 12 行,无论它从哪里开始。

2.1) 最终将第12行存储到一个变量中(这是可选的)

3) 在第 12 行之后立即终止 mycat,这样 bash 脚本就可以继续执行而不会被即将出现的 stdError 所困扰。

4) 读取行 "Channels" 的值(在本例中为 6)并将其存储到名为 "channels"

的变量中

5) 读取行 "SampleRate" 的值(在本例中为 48000)并将其存储在名为 "rate"

的变量中

有办法吗?

您可以使用 mycat shm_name > /dev/null 2>/path/to/file 重定向 stderr。时机成熟时,您可以使用 killall mycat 杀死 mycat。为了存储变量,您需要 export channels =,与速率相同的模式。您可以找到带有 grep 的那些。不过,我不确定如何准确地等待十二行。

首先,您需要将 STDERR 重定向到 STDOUT,并让 STDOUT 变为空。

mycat 2>&1 >/dev/null | parsing_script

那么你需要一个解析脚本来收集你的数据

 #!/bin/bash

declare -a data=()
count=1
while read line; do
   data+=( "$line
   ")
   ((count++))

   string=$(echo $line|sed 's/.*(\(.[A-Za-z]*\)).*//')
   case $string in
      SampleRate) rate=$(echo $line|sed 's/.*: \(.[0-9]*\) .*//')
        ;;
      Channels) channels=$(echo $line|sed 's/.*: \(.[0-9]*\) .*//')
        ;;
      *) true;;
   esac
   if [[ $count -gt 12 ]]; then
      break
   fi
done <&0

echo $channels
echo $rate

我回显了这些值,但您可以将它们重定向到文件、格式​​化它们等。另外,${data[@]} 包含您的元数据。因为你在管道,我正在从 STDIN 读取,但如果你想调整它可能会更健壮。

我找到了一个优雅的解决方案:

while read -r line;                                         # Read mycat line by line
do
    if echo "$line" | grep -qi "SampleRate"; then           # Search for line containing string 'SampleRate'
        rate="${line#*:}";                                  # Remove all charachters till ':' 
        rate="${rate%(*}";                                  # Remove all charachters from '('
        rate="$(echo -e "${rate}" | tr -d '[[:space:]]')"   # Remove all tralling withespace
    elif echo "$line" | grep -qi "Channels"; then
        channels="${line#*:}";
        channels="${channels%(*}";
        channels="$(echo -e "${channels}" | tr -d '[[:space:]]')"
    fi

    if [ -n "$channels"  ] && [ -n "$rate"  ]; then         # If both variables 'channels' and 'rate' are not empty kill the while loop
        break;
    fi
done < <(./mycat $shm_name  2>&1 > /dev/null)           # Mycat is processed into a while loop, standard Error is redirected to standard Output ( 2>&1 )

echo "Found datarate: $rate"
echo "Found channels: $channels"