명령의 첫 번째 부분에서만 forloop를 사용하는 방법

명령의 첫 번째 부분에서만 forloop를 사용하는 방법

나는이 .sh를 가지고 있습니다 :

#!/bin/bash

cd /home/pi/Desktop/PiFmRds/src

for f in $(ls -1 /home/pi/Desktop/Music/Acapella/*.mp3|sort -R); do sox -t mp3 "$f" -t wav -r 44100 - | sudo ./pi_fm_rds -freq 102.1  -audio - -ps WZSFM -rt "ZSFM"; done

기본적으로 디렉토리의 모든 파일을 무작위 순서로 재생하고, 즉시 mp3에서 wav로 변환한 다음, pfm으로 파이프합니다. Pifm은 FM 라디오로 방송할 수 있는 프로그램입니다. 문제는 forloop를 사용하고 있기 때문에 pfm 명령을 실행하여 각 개별 파일을 브로드캐스트하기 때문에 각 파일 사이의 라디오에 약간의 정적 신호가 있으므로 파일의 pfm 명령 사이의 라디오에 약간의 정적 신호가 있다는 것입니다. 그런 다음 중지하고 다음 파일 처리를 시작합니다. forloop가 명령의 첫 번째 부분만 수행하여 실제로 방송되는 pfm 부분이 아닌 임의의 노래를 선택하도록 하는 방법이 있습니까? 이렇게 하면 pfm 명령이 항상 브로드캐스트되고 for 루프는 명령이 섞이는 파일 부분에만 적용됩니다.

추가적으로 나는 이것을 시도했다:

#!/bin/bash

cd /home/pi/Desktop/PiFmRds/src

    for f in $(ls -1 /home/pi/Desktop/Music/Acapella/*.mp3|sort -R); do sox -t mp3 "$f" -t wav -r 44100 - ; done | sudo ./pi_fm_rds -freq 102.1  -audio - -ps WZSFM -rt "ZSFM"

하지만 파일을 재생한 후에는 멈춥니다.

편집: 문제를 다음과 같이 요약했습니다. 파일 사이에 정적이 있는 이유는 pifm 명령이 각 파일을 브로드캐스팅하기 때문이지만 forloop의 각 반복마다 중지하고 다시 실행하므로 반복 간에 정적만 있기 때문입니다. 각 파일을 개별적으로 반복하면서(필요한 경우, 그렇지 않으면 더 많은 문제가 발생하게 됨) 항상 방송하도록 하려면 어떻게 해야 합니까?

답변1

먼저 읽고 이해하세요.ls가 구문 분석되지 않는 이유는 무엇입니까(그리고 무엇을 해야 합니까)?ls- 당신이 하려고 하는 것처럼 그것을 사용 하지 말아야 할 타당한 이유가 있습니다 .

재생 목록을 무작위로 지정할 필요가 없다면 "그냥 find해당 -exec옵션을 사용하세요. 대신 find해당 -print0옵션을 사용하고 출력을 sort -z -R(또는 shuf -z)로 파이프한 다음 xargs -0r스크립트를 실행하여 파일을 변환하고 재생하세요.

먼저 다음과 같은 스크립트를 작성하십시오.

#!/bin/bash

pifm='/home/pi/Desktop/PiFmRds/src/pi_fm_rds'

for f in "$@"; do
  sox -t mp3 "$f" -t wav -r 44100 -
done | sudo "$pifm" -freq 102.1  -audio - -ps WZSFM -rt "ZSFM"

.lspi_fm_rds

그런데, 추가 줄바꿈과 들여쓰기를 추가하여 스크립트를 더 쉽게 읽을 수 있도록 노력해야 합니다. \줄 끝에 백슬래시()를 추가하면 다음 줄이 현재 줄의 연속임을 bash에 알릴 수 있습니다 . 또는 아래의 다음 스크립트에 표시된 것처럼 |파이프 문자( )로 끝나는 줄은 \.

아직 수행하지 않은 경우 sudo사용자가 암호 없이 루트로 실행할 수 있도록 구성해야 합니다 ./home/pi/Desktop/PiFmRds/src/pi_fm_rds

예를 들어 /usr/local/bin/randomise-playlist.sh로 저장하고 실행 가능하게 만듭니다 chmod +x /usr/local/bin/randomise-playlist.sh.

그런 다음 변환하고 재생할 파일 이름 목록을 전달하여 다음과 같이 실행하십시오.

find /home/pi/Desktop/Music/Acapella/ -type f -name '*.mp3' -print0 |
  sort -z -R |
  xargs -0 -r /usr/local/bin/randomise-playlist.sh

shuf -z또는 대신 -shuf를 사용하십시오 sort -z -R. shuf의 목적은 입력 라인을 무작위로 지정하는 것입니다.

이는 파이프라인 전체에서 파일 이름 구분 기호로 NUL을 사용하기 때문에 유효한 문자(공백, 탭, 줄 바꿈 및 &및와 같은 셸 메타 문자도 포함)가 포함된 ;파일 이름을 사용합니다.

그건 그렇고, 어떤 사람들은 항상 연속된 줄을 끝내고 다음 줄의 시작 부분에 \파이프 |문자(또는 ||기타 등등)를 넣는 것을 좋아합니다. &&두 방법 모두 동일하게 작동하므로 더 읽기 쉬운 방법을 선택하세요. 하지만 항상 몇 개의 공백(보통 2개의 공백을 사용합니다. 4개의 공백도 좋습니다. 또는 때로는 후속 행의 동일한 열에서 시작하도록 매개변수를 정렬하려고 합니다) 또는 표 기호로 연속된 줄을 들여쓰는 것이 좋습니다. 이전 줄의 연속임을 나타냅니다.

find /home/pi/Desktop/Music/Acapella/ -type f -name '*.mp3' -print0 \
  | sort -z -R \
  | xargs -0 -r /usr/local/bin/randomise-playlist.sh

위의 모든 항목 에는 GNU 버전 find및 /또는 가 필요합니다 . Raspberry Pi에서 실행 중이므로 GNU가 표준이어야 합니다 .xargssortshufcoreutilsfindutils

원하는 경우 전체 find ... | xargs명령을 자체 스크립트에 넣을 수 있습니다. 실행할 때마다 입력하는 데 시간이 조금 걸립니다.

답변2

for 루프를 사용하여 각 클립을 개별적으로 재생하는 대신 sox 명령의 기능을 사용하여 클립을 단일 재생 스트림으로 결합합니다.

또한 파일 이름에 특수 문자(공백 포함)가 있으면 목록을 생성하는 지정된 방법이 중단됩니다. 또한 파일 수가 많으면 명령줄 길이 제한에 도달할 수 있습니다. 원래 명령에는 두 가지 문제가 모두 있으므로 이 문제를 완전히 해결하지는 않겠습니다. 그러나 가능한 해결책은 파일 이름을 임의의 순서로(아마도 심볼릭 링크와 같이) 새로운 번호가 매겨진 파일 이름에 매핑한 다음 이를 단일 이름으로 sox에 제공하고 -t mp3 "*.mp3"sox가 전역적으로 확장되도록 허용하는 것입니다.

다음 변경 사항이 귀하의 요구 사항을 충족해야 합니다.

  • 루프에서 sox를 ​​실행하는 대신 파일 목록을 sox에 직접 제공하십시오.

  • -t mp3옵션을 제거하고 sox가 자동으로 파일 형식을 감지하도록 하세요.

  • 모든 .mp3 파일이 동일한 샘플링 속도와 채널 수를 사용하여 연결된 단일 출력 스트림으로 결합될 수 있는지 확인하세요.

    sox $(ls -1 /home/pi/Desktop/Music/Acapella/*.mp3|sort -R) -t wav -r 44100 - | sudo ./pi_fm_rds -freq 102.1 -audio- -ps WZSFM -rt "ZSFM "

위의 작업 중 하나라도 실패하면 파일을 병합하기 전에 파일을 사전 처리해야 할 수 있습니다.

오디오 파일에는 기본적으로 헤더가 있고 직접 추가할 수 없기 때문에 두 번째 시도가 실패했습니다. pi_fm_rds 명령에 대한 문서를 확인하지 않으면 해당 헤더가 필요한지 알 수 없습니다. 예상하지 못한 경우 이는 파일 간의 정적 소스일 수 있습니다. 이 경우 또 다른 접근 방식은 헤더 없이 원시 오디오를 내보내고 for 루프의 각 파일에 대해 개별적으로 계속 호출하도록 sox에 지시하는 것입니다.

관련 정보