bash在while循环期间正在吃字符

时间:2017-04-09 11:36:28

标签: bash while-loop

为什么bash会在下面的循环中吃掉一些字符?

#!/bin/bash

INPUT_DIR=$1
OUTPUT_DIR=$2

rm -rf  "${OUTPUT_DIR}"
mkdir -p "${OUTPUT_DIR}"

cd "${INPUT_DIR}" && find . -type f -name '*.m4a' | while IFS= read -r original
do
    TMPFILE="$(mktemp --dry-run)"
    IN_FILE="${INPUT_DIR}/${original}"
    OUT_FILE="${OUTPUT_DIR}/${original/.m4a/.wav}"
    echo "${IN_FILE} => ${TMPFILE} => ${OUT_FILE}"
    (cd "${INPUT_DIR}" \
        && ffmpeg -i "${IN_FILE}" -y -f wav -acodec pcm_s16le -ac 2 "${TMPFILE}" \
    )
    # ... do something with "${TMPFILE}", save as ${OUT_FILE}
    test -e "${TMPFILE}" && rm "${TMPFILE}"
done

当离开ffmpeg行时,${IN_FILE}开头的部分字符丢失,导致ffmpeg失败(找不到文件)。 echo命令的输出中也缺少字符。

但是,从脚本中删除ffmpeg行时,echo命令的输出看起来不错。

2 个答案:

答案 0 :(得分:3)

假设在循环的第一次迭代中没有发生这种情况,很可能ffmpeg正在消耗它的一些stdin,并且它当前正在读取与while循环相同的流。只需关闭其输入:

do
    TMPFILE="$(mktemp --dry-run)"
    IN_FILE="${INPUT_DIR}/${original}"
    OUT_FILE="${OUTPUT_DIR}/${original/.m4a/.wav}"
    echo "${IN_FILE} => ${TMPFILE} => ${OUT_FILE}"
    (cd "${INPUT_DIR}" \
        && ffmpeg <&1- -i "${IN_FILE}" -y -f wav -acodec pcm_s16le -ac 2 "${TMPFILE}" \
    )
    # ... do something with "${TMPFILE}", save as ${OUT_FILE}
    test -e "${TMPFILE}" && rm "${TMPFILE}"
done

答案 1 :(得分:1)

作为将用于循环的流与循环体使用的流分离的一般方法,您可以执行以下操作:

while IFS= read -u 5 -r original
do
  # Loop body
done 5< <(cd "${INPUT_DIR}" && find . -type f -name '*.m4a')

此示例使用文件描述符5(以及进程替换)。这非常有用,例如,如果你想要一个循环体来执行read语句或其他需要用户输入的命令,那么这些命令将无法从与循环相同的流中读取{{ 1}}语句,而不是来自终端。

防止read访问标准输入,如单独的答案所示,仍然是一个好主意,因为虽然您的循环流受到保护,但您可能仍然在上下文的标准输入上有可用的内容仍然希望保护ffmpeg无法阅读。

此外,您可能希望对文件名使用空分隔符,这样可以处理名称中包含特殊字符的文件(即换行符)。您只需要对ffmpegread命令进行细微更改。

find