저는 스크립트를 작성하거나 명령을 찾는 전문가가 아닙니다(단지 경고임). 나는 내 모든 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/ \;
-execdir
POSIX 표준의 확장이지만 많은 최신 구현에서 지원 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