2017-04-09 9 views
2

なぜwhileループ中にbashがいくつかの文字を食べるのですか? whileループ中に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コマンドの出力が正常に表示されます。

+0

2つの入力引数の例と、関連するエコー行に欠損文字がありますか? – Dunatotatos

答えて

1

を、次の操作を実行できます。

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

この例では、ファイルを使用しています記述子5(プロセス置換と一緒に)たとえば、readステートメントやユーザー入力を必要とするコマンドを実行するループ本体を作成したい場合、これらのコマンドはループreadステートメントではなく、同じストリームから読み込むことになります。ターミナル。

ループストリームが保護されているにもかかわらず、依然として必要とするコンテキストの標準入力に何かが残っている可能性があるため、別の回答で示唆されているようにffmpegが標準入力にアクセスするのを防ぐ読むためにffmpegによって何らかの試みから守るために。

また、ファイル名にヌルデリミタを使用すると、名前に特殊文字を含むファイル(改行など)を扱うことができます。 readfindコマンドに少し変更するだけで済みます。

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

この解答はありがとうございます。それは私の問題の根本的な原因を理解するのを助けました。 – dubbaluga

+0

これは実際には非常に便利で、私がこのことについて自分自身で見つけたとき、私にとっては多くのことを変えました。 – Fred

+0

ループ内にループを入れ子にすることができ、両方に同じファイル記述子番号を使用することができます。それらは混在しません。 "5"は私の個人的な基準です(正当な理由なし)。ループが特に入力を標準入力(すなわち "フィルタリング"機能)から供給されない限り、基本的にはすべてのループに使用します。このようにして、ソースで問題を回避します(これらの問題は明らかではないため、デバッグが難しい場合があります)。 – Fred

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 
+0

または '(cd ... && ffmpeg ...)<<<" "'(明示的な '<&1-'ははるかに良いです:) – jm666

+0

あなたの答えをありがとう!あなたの提案は私のために働いたし、他の答えがない場合は、私はこれを最も有益なものとして選んだだろう。 – dubbaluga

関連する問題