Bash 스크립트에서 이상한 문자를 올바르게 이스케이프 처리하는 방법은 무엇입니까?

Bash 스크립트에서 이상한 문자를 올바르게 이스케이프 처리하는 방법은 무엇입니까?

저는 스크립트를 작성하거나 명령을 찾는 전문가가 아닙니다(단지 경고임). 나는 내 모든 mp3 팟캐스트를 내 휴대폰으로 이동할 수 있는 폴더로 이동하는 스크립트를 만들려고 합니다.

그래서 제가 만든 스크립트는 모든 mp3(경로가 이상한 파일도 포함)를 이동해야 합니다. 아래와 같이 스크립트를 작성했는데 의도한 대로 작동하는 것 같은데 계속해서 다음과 같은 오류가 발생합니다.

find /home/jason/gPodder/ -name '*.mp3' -exec bash " cp '{}' /home/jason/gPodder/mp3/ " \;
Which returns:    
bash:  cp '/home/jason/gPodder/Downloads/The Documentary/TheDocumentary20170823-GoingGreenInTheOilState.mp3' /home/jason/gPodder/mp3/ : No such file or directory 

하지만 위의 bash "명령"을 복사하면 제대로 작동합니다. 스크립트의 오류가 무엇인지 이해하도록 도와주세요.

감사해요

답변1

~처럼@Kusalananda가 말했습니다.-c, 인라인 스크립트를 사용하는 기능이 없습니다 .

{}그러나 그럼에도 불구하고 임의의 명령 주입 취약점(예: '$(reboot)'.mp3예제에서 호출된 파일) 이 될 수 있는 셸 코드에 포함되어서는 안 됩니다 . 대신, 인라인 스크립트에 대한 매개변수로 만드십시오(인라인 스크립트가 실제로 필요하다고 가정하고 이는 cp단지 예일 뿐입니다).

find ... -exec sh -c 'cp "$1" /home/jason/gPodder/mp3' sh {} \;

bash( 이것만을 위해서도 할 필요는 없습니다 . sh의지도 괜찮습니다.)

또는 더 나은 방법은 한 번에 여러 인수를 전달하는 것입니다 cp.

find ... -exec sh -c 'cp "$@" /home/jason/gPodder/mp3' sh {} +

GNU를 사용하면 cp다음을 수행할 수도 있습니다.

find ... -exec cp -t /home/jason/gPodder/mp3 {} +

답변2

필요 이상으로 복잡하게 만들지 마십시오.

find /home/jason/gPodder/ -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

아니면 어쩌면

find /home/jason/gPodder/ -type f -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

일반 파일만 고려됩니다.

동일한 이름의 파일이 대상 폴더에 없는 경우에만 파일을 복사하십시오. 일부 cp구현에서는 이 옵션을 지원 하거나 다음에서 리디렉션된 표준 입력을 -n사용할 수 있습니다 (그러나 대상 유형이 디렉토리인 경우에는 작동하지 않습니다). 다음과 같이 하십시오:-i/dev/null

find /home/jason/gPodder/ -type f -name '*.mp3' \
    ! -execdir test -e /home/jason/gPodder/mp3/{} \; \
    -exec cp {} /home/jason/gPodder/mp3/ \;

-execdirPOSIX 표준의 확장이지만 많은 최신 구현에서 지원 find됩니다 . find유사하게 실행되지만 -exec발견된 콘텐츠의 상위 디렉터리를 작업 디렉터리로 사용하여 명령을 실행합니다. 또한 전체 경로가 아닌 {}발견된 항목( file.mp3또는 구현 ./file.mp3에 따라 )의 기본 이름이 됩니다. find바라보다 man find.


이 오류는 에서 발생합니다 bash "somecommand". bash이 방법으로 호출하면 일련의 셸 명령이 아닌 스크립트 파일의 경로가 bash필요하며 somecommand지정한 이름의 스크립트를 찾을 수 없습니다.

일련의 쉘 명령을 실행하려면 가 필요합니다 bash -c "somecommand".

하지만 이 경우에는 -exec cp위의 방법이나 다음의 방법을 사용하세요.Stefan Chazeras의 답변.

답변3

다른 사람들은 가격 책정 및 실행 문제를 지적했습니다.

find -exec를 사용하는 대신 xargs 및 cp에 대한 목록과 파이프 목록을 찾는 것이 좋습니다. print0 옵션을 사용하면 파일 및 디렉터리 이름에 "재미있는" 문자를 방지하는 데 도움이 됩니다.

예를 들어

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 cp -t destinationpath

이것의 장점은 xargs가 find에서 여러 파일 이름을 수집하여 동시에 cp에 전달하므로 각 파일에 대해 1 cp 호출을 실행하는 대신 각 cp 인스턴스가 20 또는 100개의 파일을 복사할 수 있다는 것입니다. xargs는 cp 명령줄에 충분한 파일 이름을 입력합니다.

xargs에 -P n 옵션을 추가하면 여러 cp 프로세스가 병렬로 시작됩니다.

이는 파일이 대상 mp3 폴더와 동일한 파일 시스템에 있다고 가정합니다. cp에 -l을 추가하면 파일을 복사하는 대신 대상에 하드 링크됩니다.

예를 들어

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 -P 5 \
    cp -l -t destinationpath

관련 정보