find 명령에서 파이프된 파일 이름 조작

find 명령에서 파이프된 파일 이름 조작

저는 Bash를 처음 접했고 표면적으로 매우 간단해 보이는 작업을 수행하려고 합니다. 디렉토리 계층 구조에서 find를 실행하여 모든 *.wma 파일을 가져오고 출력을 mp3로 변환하는 명령으로 파이프한 다음 변환된 파일을 .mp3로 저장하세요. 내 생각에는 명령이 다음과 같아야 한다는 것입니다(오디오 변환 명령을 포기하고 대신 설명을 위해 에코를 사용했습니다).

$ find ./ -name '*.wma' -type f -print0 | xargs -0 -I f echo ${f%.*}.mp3

내가 이해한 바로는 -print0 인수를 사용하면 공백이 포함된 파일 이름을 처리할 수 있습니다(대부분 공백이 음악 파일이기 때문입니다). 그런 다음 (xargs로 인해) find의 모든 파일 경로가 f에 캡처되고 문자열 끝에서 하위 문자열 일치/제거를 사용하여 wma 대신 mp3를 사용하여 원래 파일 경로 확장자를 에코해야 합니다. 그러나 이 결과 대신 다음이 표시됩니다.

*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
...

그래서 내 질문은("내가 여기서 뭘 잘못하고 있는 거지?"라는 구체적인 질문 외에도) 문자열 조작 작업에서 파이프 작업의 결과인 값을 파이프 작업의 결과인 값과 다르게 처리해야 합니까? 변수 할당?

답변1

다른 답변이 이미 설정되었으므로 ${f%.*}명령을 실행하기 전에 셸에 의해 확장됩니다 xargs. 각 파일 이름을 한 번 확장하고 셸 변수를 파일 이름으로 설정해야 합니다 f(통과에서는 -I f그렇게 하지 않습니다. 셸 변수에 대한 개념이 없으며 명령에서 문자열을 찾습니다 xargs. 따라서 f예를 들어 사용 하면 xargs -I e echo …뭔가를 수행합니다 . 처럼 ./somedir/somefile.wmacho .mp3) 명령.

이 접근 방식을 계속해서 xargs호출 셸에 확장을 실행할 수 있음을 알립니다. 더 좋은 점은, Tell은 find정확하게 xargs사용하기 어려운 상당히 오래된 도구라는 것입니다. 왜냐하면 최신 버전의 find는 동일한 작업(및 그 이상)을 수행하지만 파이프라인 난이도가 덜한 구조를 갖기 때문입니다. 대신 find … -print0 | xargs -0 command …을 실행하십시오 find … -exec command … {} +.

find . -name '*.wma' -type f -exec sh -c 'for f; do echo "${f%.*}.mp3"; done' _ {} +

인수는 셸 _에 있습니다 . 파일 이름은 위치 인수로 루프에 전달됩니다. 이 명령의 간단한 버전은 각 파일에 대해 별도의 셸을 실행합니다. 이는 동일하지만 약간 느립니다.$0for f; do …

find . -name '*.wma' -type f -exec sh -c 'echo "${0%.*}.mp3"' {} \;

find상당히 새로운 쉘(ksh93, bash ≥4.0 또는 zsh)을 실행한다고 가정하면 여기서는 실제로 사용할 필요가 없습니다. bash에서 하위 디렉터리(ksh에서는 )에서 반복하려면 glob 모드를 활성화하려면 입력 shopt -s globstar하세요 . 그럼 당신은 실행할 수 있습니다.bashrc**/set -o globstar

for f in **/*.wma; do
  echo "${f%.*}.mp3"
done

(이라는 이름의 디렉터리가 있는 경우 *.wma루프 [ -f "$f" ] || continue시작 부분에 추가하세요.)

답변2

${f%.*}.mp3를 평가하는 솔루션이 전체 명령을 호출하는 셸에서 수행되는 경우매개변수. 당신의 껍질에는 없습니다에프변수는 빈 문자열로 대체됩니다.

솔루션 활용매개변수그리고-만약에:

% cat 1.sh 
#!/bin/sh
f=$1
echo ${f%.*}.mp3
% /bin/ls -1
1.sh
aaa.wma
bbbb.wma
ccccc.wma
% find ./ -name '*.wma' -type f -print0 | xargs -0 -I f ./1.sh f
./aaa.mp3
./ccccc.mp3
./bbbb.mp3

하지만 나는 이렇게 할 것이다:

% find ./ -name '*.wma' -type f | sed 's,\.wma$,.mp3,'

관련 정보