Bash 停止录制而不停止脚本的其余部分

Bash 停止录制而不停止脚本的其余部分,bash,Bash,我正在玩使用谷歌语音到文本api的脚本。api需要flac编码的文件,因此脚本的录制部分如下所示: arecord -q -t wav -d 0 -f S16_LE -r 16000 | flac - -f --best --sample-rate 16000 -s -o "$TEMP_FILE" 此命令将记录,直到用户使用ctrl-c退出,wav记录的格式应通过管道传输到flac程序,以flac格式输出,然后脚本应继续 我遇到的问题是,按ctrl-c键会完全结束脚本,并切断部分音频(flac

我正在玩使用谷歌语音到文本api的脚本。api需要flac编码的文件,因此脚本的录制部分如下所示:

arecord -q -t wav -d 0 -f S16_LE -r 16000 | flac - -f --best --sample-rate 16000 -s -o "$TEMP_FILE"
此命令将记录,直到用户使用ctrl-c退出,wav记录的格式应通过管道传输到flac程序,以flac格式输出,然后脚本应继续

我遇到的问题是,按ctrl-c键会完全结束脚本,并切断部分音频(flac文件仍在输出)。如果在不使用管道的情况下运行脚本:

arecord -q -t wav -d 0 -f S16_LE -r 16000 some.wav
然后按ctrl-c键只会结束录制并继续使用脚本


如何修复此问题,使ctrl-c只停止arecord命令,并允许脚本的其余部分(包括管道flac编码)完成?

我认为您试图做的事情无法完成

免责声明:以下内容基于我自己在Ubuntu 12.04上的实验,只是一点研究。如果我错了,一定要告诉我

关键是:

  • 在管道运行时按Ctrl-C将向管道中的所有进程发送信号
    SIGINT
  • 进程接收信号的顺序无法保证
  • 除非管道中的所有进程都捕获信号,否则脚本将作为一个整体中止(尽管脚本本身可以使用
    trap
    命令捕获信号-但这样的shell陷阱在管道进程接收到信号并通常被其终止后才会执行)
在您的特定情况下,
arecord
设计用于捕获
SIGINT
并以有序的方式退出。
相比之下,
flac
似乎没有-它被强制终止。
但是,即使
flac
也确实捕获了
SIGINT
以干净地关闭,由于相关进程接收信号的顺序不确定,您无法安全地使用带有Ctrl-C的管道,同时期望整个处理以有序的方式完成。

(顺便提一下:
arecord
在使用Ctrl-C终止时报告退出代码
1
,这让我想知道如何将其与真正的故障区分开来,例如磁盘空间不足。)

因此:

  • arecord
    作为单独的命令调用
    并将输出捕获到(临时)文件中
  • 然后,将(临时)文件传递到
    flac
    (完成后删除临时文件)
    • 我将尝试以下方法:

      # Create a fifo
      FIFO=/tmp/my_fifo
      mkfifo $FIFO
      
      # Start arecord in background and redirect its output into the fifo
      arecord ... > $FIFO &
      
      # Get the arecord PID
      PID=$!
      
      # Trap the SIGINT to send SIGINT to arecord
      trap "kill -INT $PID" INT
      
      # Start flac and redirect its input with the fifo.
      flac - ... < $FIFO
      
      # The script should be blocked here, and a CTRL+C will run
      # the kill -INT to the arecord process only.
      # But I don't know how flac will react after ...
      # If flac exit correctly, just restore the SIGINT
      trap - INT
      
      #创建fifo
      先进先出=/tmp/my_先进先出
      mkfifo$FIFO
      #在后台启动一条记录,并将其输出重定向到fifo
      A记录…>$先进先出&
      #获取arecord PID
      PID=$!
      #捕获SIGINT以将SIGINT发送到arecord
      陷阱“kill-INT$PID”INT
      #启动flac并用fifo重定向其输入。
      flac-…<$先进先出
      #应该在此处阻止脚本,并运行CTRL+C
      #kill-INT仅用于arecord进程。
      #但我不知道flac在。。。
      #如果flac正确退出,只需恢复SIGINT
      陷阱整数
      
      问题在于
      Ctrl-C
      会杀死
      flac
      ,因为
      flac
      的设计不是以这种方式完全关闭的(不像
      arecord
      )。现在需要的是一种在
      Ctrl-C
      到达
      flac
      之前拦截
      Ctrl-C的方法,这是您的解决方案无法做到的(陷阱在
      flac
      已经被杀死之后启动)-我不知道如何在bash中做到这一点。此外,我想知道OP追求的是单一管道的优雅。如果不能做到这一点,那么只需记录到一个临时的。文件,然后对临时文件进行转码。文件要简单得多。