$()가 올바르게 확장되지 않는 이유는 무엇입니까?

$()가 올바르게 확장되지 않는 이유는 무엇입니까?

vlc를 사용하여 디렉토리의 모든 .mp3 파일을 재생하고 싶으므로 다음과 같이 합니다.

vlc $(find ~/Documents/music -name "*.mp3" -exec "echo \"{}\"" \;)

문제는 "vlc: 알 수 없는 옵션 또는 필수 매개변수 '-D'가 누락되었습니다"라는 메시지가 표시된다는 것입니다. 아마도 구문 분석 문제일 것입니다.

그럼 파일별로 해보자:

echo $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)

나는 얻다:

"/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"

내가 실행할 때 :

vlc "/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"

효과가있다.

하지만 내가 달릴 때

vlc $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)

나는 얻다:

cannot open file /home/XXX/the (No such file or directory)

vlc의 인수가 올바르게 인용되지 않은 경우 이는 의미가 있습니다. 하지만 그렇습니까? 그렇다면 왜 인용되지 않은 문자열로 vlc에 전달됩니까?

답변1

확장된 출력에서는 견적이 처리되지 않습니다. $(echo '"foo bar"')or 를 수행하는 경우 $(echo "\"foo bar\"")기본 명령에 대한 인수는 "fooand 입니다 bar". 리터럴 따옴표와 두 개의 다른 인수를 사용하십시오.분사.

기본적으로 단어 분리는 모든 공백, 공백 또는 개행 문자에서 발생하므로 의 출력에서는 어떤 공백이 파일 이름의 일부인지, 어떤 공백이 이를 구분하는 데 사용된 인쇄 내용의 일부 find인지 알 수 없습니다 . find일반적인 경우에도 파일 이름에 개행 문자가 포함될 수 있으므로 구분할 수 없습니다.

당신이 할 수 있는 일은 다음과 같습니다:

find ... -print0 | xargs -0 vlc 

또는

find ... -exec vlc {} +

첫 번째는 findNUL 바이트로 구분된 파일 이름을 출력하고 xargs예상되는 내용을 알려줍니다. 그러나 모든 시스템에 find -print0및 가 있는 것은 아닙니다 xargs -0.

두 번째 함수 find자체가 시작되고 vlc꼬리 {} +는 여러 파일 이름을 vlc.

많은 수의 파일을 찾고 있는데 하나의 명령줄에 들어갈 수 없는 경우 두 파일 모두 vlc여러 번 시작될 수 있습니다.

바라보다:

디버깅에 이것을 사용하면 echo인수가 공백으로 연결되어 , echo foo bar및 를 구별할 수 없게 되므로 실제로 작동하지 않습니다 echo "foo bar".

답변2

확장은 $()정확하지만 쉘은 여러분이 생각하는 것보다 더 많은 결과를 제공합니다. 또한 경로 이름에 문자 그대로 따옴표를 추가하는 것은 (어딘가에서 사용하지 않는 한) 거의 올바른 일이 아닙니다 eval.

이하의 모든 MP3 파일을 재생하려면 다음을 ~/Documents/music사용하십시오 vlc.

find ~/Documents/music -type f -name '*.mp3' -exec vlc {} +

vlc이렇게 하면 한 번에 가능한 많은 MP3 파일이 실행 됩니다 .

find모두 함께 사용하여 건너뛰려면 다음을 수행하세요 .

shopt -s globstar
vlc ~/Documents/music/**/*.mp3

이 방법은 MP3 파일 수가 많지 않은 한 작동합니다(이 경우 매개변수 목록이 너무 길어서 오류가 발생합니다).

glob은 **파일 계층 구조와 "재귀적으로" 일치하지만 셸을 사용하여 shopt -s globstar활성화 해야 합니다 bash( zsh이 glob은 기본적으로 활성화되어 있습니다).


주문

vlc $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)

먼저 실행 find하면 파이프라인이 출력됩니다 head.echo

"/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"

그러면 쉘은 문자열을 문자열 내의 단어 "/home/XXX/Documents/music/My, Folder/1, -, track/the, name, of및 공백으로 분할합니다.track.mp3"

vlc그러면 그걸로 불릴 거야분리논쟁. 특히 이 -매개변수는 옵션으로 오인될 수 있으며, 다른 매개변수는 별도의 경로 이름 피연산자로 처리될 가능성이 높습니다.

이에 대해 자세히 설명되어 있습니다.

관련 정보