ffmpeg에 전달되면 Bash 변수가 잘립니다.

ffmpeg에 전달되면 Bash 변수가 잘립니다.

.flac11개의 오디오 파일이 포함된 앨범이 있습니다. (편집하다:이 문제가 해결되었으므로 이제 파일의 정확한 이름과 내용이 관련이 없다는 것이 명백하므로 이름을 변경했습니다.)

> find . -name "*.flac"
./two.flac
./ten.flac
./nine.flac
./eight.flac
./seven.flac
./three.flac
./four.flac
./five.flac
./one.flac
./eleven.flac
./six.flac

.wav특정 샘플 속도와 비트 깊이를 가진 파일 로 변환합니다 . 저는 ffmpeg이 작업을 위해 Bash 쉘을 사용합니다. 다음과 같은 명령을 수동으로 호출하면 11개 파일 각각에 대해 완벽하게 작동합니다.

ffmpeg -i "./six.flac" -sample_fmt s16 -ar 44100 "./six.wav"

while그러나 각 파일에 대해 이 명령을 실행하기 위해 루프를 작성할 때 :

find . -name "*.flac" | sed "s/\.flac$//" | while read f; do ffmpeg -i "$f.flac" -sample_fmt s16 -ar 44100 "$f.wav"; done

이것은 작동하지만 8/11의 파일에만 해당되며 ffmpeg세 가지 실패에 대해 다음과 같은 오류 메시지가 표시됩니다.

/ten.flac: No such file or directory
ree.flac: No such file or directory
ix.flac: No such file or directory

의 경우 ./ten.flac상대 파일 경로의 선행 부분이 .잘려 절대 경로를 형성하는 반면, 다른 두 개 ./three.flac및 의 ./six.flac경우 기본 이름의 시작 부분을 포함하여 더 많은 문자가 손실됩니다. 다른 8개 파일 중 일부가 ./잘렸지만 이로 인해 올바른 상대 경로가 생성되었으므로 ffmpeg이러한 경우에는 계속할 수 있었습니다.

동일한 루프 구조를 사용하지만 echo "$f"call 대신 사용하면 ffmpeg출력에 문제가 없다고 생각합니다.

> find . -name "*.flac" | sed "s/\.flac$//" | while read f; do echo "$f"; done
./two
./ten
./nine
./seven
./three
./four
./five
./one
./eleven
./six

"$f"따라서 루프가 잘 구조화되어 있고 각 반복에서 내가 기대하는 방식으로 확장된다고 확신합니다 . 어쨌든 "$f.flac"에 전달될 때 문자열의 일부가 잘리지 ffmpeg만 특정 파일에만 해당됩니다.

첫 번째 시도에서 이러한 동작이 나타나는 이유를 알고 싶습니다. 나는 파일을 반복하거나 변환하는 것에 대한 대안을 찾고 있지 않습니다. (다른 유형의 루프를 사용한 두 번째 시도는 모든 파일에 성공했습니다.)


편집하다:나는 문제를 해결하는 것처럼 yes |보이는 배관을 우연히 발견했습니다 . ffmpeg기존 파일을 덮어쓰라는 메시지가 표시되지 않도록 이것을 추가했습니다 .wav.

편집하다:설명해주신 @roaima에게 감사드립니다! ffmpegread가지 모두 동일한 표준 입력 핸들을 상속하므로 기회가 생기기도 전에 ffmpeg각 줄의 시작 부분에 있는 문자를 소비하여 read일부 파일 경로가 손상될 수 있습니다. 이는 표준 입력에 대해 다른 핸들을 yes | ffmpeg ...제공하기 때문에 이것이 작동하는 이유를 설명합니다 . ffmpeg원래 루프는 잘 작동합니다 ffmpeg -nostdin ....http://mywiki.wooledge.org/BashFAQ/089.

답변1

파일의 디렉터리 트리(예제 데이터 세트에 언급되지 않고 표시되지 않음)가 없으면 간단한 루프를 사용하여 파일을 처리할 수 있습니다.

for f in *.flac
do
    w="${f%.flac}.wav"
    ffmpeg -i "$f" -sample_fmt s16 -ar 44100 "$w"
done

파일 계층 구조가 있는 경우 이를 find검색 에 통합할 수 있습니다.

find -type f -name '*.flac" -exec sh -c 'for f in "$@"; do w="${f%.flac}.wav"; ffmpeg -i "$f" -sample_fmt s16 -ar 44100 "$w"; done' _ {} +

flac효율성을 위해 이미 해당 가 있는 할당 추가를 건너뛰는 것이 좋습니다 wav. 실제로 이를 원하지 않는 경우 명령을 추가로 최적화할 수 있습니다.w=[ -s "$w" ] && continue

find -type f -name '*.flac" -exec sh -c 'ffmpeg -i "$1" -sample_fmt s16 -ar 44100 "${1%.flac}.wav";' _ {} \;

사전 실행 테스트의 경우 접두사를 추가하여 실제 실행 없이 실행될 항목을 확인하세요 ffmpeg. echo(단, 인용문은 표시되지 않으니 주의하시기 바랍니다.)


ffmpeg실제로 문제는 처리해야 할 파일 이름을 씹는 것과 관련된 것으로 밝혀졌습니다 . 이는 ffmpeg읽기 명령이표준 입력, 파일 목록은 루프의 파이프로 렌더링되었습니다 while read …(또한 다음을 사용하여표준 입력).

해결책: ffmpeg -nostdin …또는ffmpeg … </dev/null

바라보다

관련 정보