변수 확장이있는 bash 스크립트에서 -exec 찾기


14

bash 스크립트에서 아래 명령과 비슷한 명령을 실행하려고합니다. 모든 하위 폴더를 검색 $sourcedir하고 특정 유형의 모든 파일을 루트 수준으로 복사해야합니다 $targetdir.

#!/bin/bash

# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;

즉 제외하고 이것은 아주 가까이 보인다 {}으로 전달되지 않는 $2-exec sh -c ...

파일 이름의 특수 문자 (특히 작은 따옴표 문자)를 허용하여 가능한 한 "올바른 방법"에 가깝게 작업하고 싶습니다.

편집 : 사람들이 사용 xargs하거나 인수 체인을 제안하는 것을 봅니다 . 나는 이것이 제한된 수의 주장에 대해서만 괜찮다는 인상을 받았다. 예를 들어 수천 개의 .jpg 파일을 여러 갤러리 디렉토리에서 거대한 슬라이드 쇼 디렉토리로 복사하려고하면 솔루션 체인 인수가 여전히 작동합니까?

편집 2 : 내 문제는 명령 _에서 sh 할 첫 번째 옵션 이전 에 누락되었다는 것 -exec입니다. find 명령을 작동시키는 방법에 대해 궁금한 사람은 다음을 추가하십시오 _.

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;

동일한 작업을 수행하지만보다 효율적이고 우아하기 때문에 아래 답변을 수락했습니다.


4
이것이 바로 xargs한계가있는 일반 명령에서 많은 양의 인수를 자동으로 처리하기 위해 작성된 이유 입니다. 또한 고려할 수있는 대부분의 최대 인수 제한은 표준 GNU 유틸리티에 대해 크게 개선되었습니다. 또한 수천 개의 파일과 관련된 프로세스 포크를 피하면서 성능상의 이점을 볼 수 있습니다.
JM Becker

";"대신 gnu-find 및 +를 사용하면 find를 사용하여 여러 인수를 한 번에 처리 할 수 ​​있습니다. 그리고 -print0으로 전달되는 복잡한 인수를 저장합니다.
사용자 알 수 없음

@ userunknown : 귀하의 답변 아래에 이것에 응답하고 있습니다.
JM Becker

@user unknown 글쎄, 나는이 코드를 좋아한다. 최소한 POSIX 와 완벽하게 호환 되며 시스템에 GNU 기능이 전혀 없어도 작동합니다. 이 때 그 시간이 있습니다 않습니다 특히 직장에서 서버에서이 필요합니다.
syntaxerror

답변:


6

특정 유형의 파일을 특정 디렉토리로 복사 하시겠습니까? 이것은 가장 잘 수행되며 xargs필요하지도 않습니다 sh. 이것은 더 적절한 방법이며 더 효율적으로 실행되어야합니다.

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

특수 파일 이름을 처리해야하는 경우 NULL구분자 로 사용 하십시오.

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"

1
두 번째 경우에, 추가하는 것을 잊지 마세요 -print0find-0xargs
SiegeX

@ SiegeX는 귀하의 의견을 알기 전에 이미 그렇게했습니다.
JM Becker

또한를 NULL사용하는 경우 필요 '{}'하지 않습니다. POSIX컴플라이언스 이외의 다른 하나의 진정한 이점 은 성능입니다.
JM Becker

6

{}쉘에 인수 로 전달한 다음 각 인수를 반복해야합니다.

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

참고 : 이것이 작동하는 방식은 쉘에 대한 첫 번째 인수가 쉘의 이름이라는 것입니다 . 이름을로 전달하여이를 악용 $targetdir한 다음 $0쉘 스크립트 내부의 특수 매개 변수를 사용하여 해당 대상 디렉토리 에 액세스 할 수 있습니다.


1
"$targetdir"작은 따옴표 안에 확장되지 않습니다.
enzotib

5

xargs의 교회를 믿지 않는다면 :

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

설명:

cp -t a b c d 

b, c 및 d를 대상 디렉토리 a에 복사합니다.

-exec cmd {} +

한 번에 하나씩이 아니라 한 번에 많은 파일에서 명령을 호출합니다 ( ";"대신에 사용 하는 경우 표준 임)+ ). 그렇기 때문에 targetdir을 앞으로 가져와 명시 적으로 대상으로 표시해야합니다.

이것은 gnu-find에서 작동하며 find의 다른 구현에서는 그렇지 않을 수 있습니다. 물론 그것은 -t -flag에도 의존합니다.

TechZilla는 물론 지금까지는 shcp를 호출 할 필요가 없기 .

xargs과 함께 불필요한 시간을 사용하지 않으면 및 플래그 find를 학습 하지 않아도됩니다 .-print0-0


1
분명히, 어떤 사람이 선호 할 수있는 방법은 다소 주관적입니다. 그 말에도 불구하고 여전히 사용할 이유가 있습니다 xargs. 가장 큰 예, 파일을 찾지 못하면 어떻게됩니까? 나는 for항상 일반적인 루프 대신 xargs를 사용 find하고 범위가 훨씬 작습니다. 또한 GNU를 사용 find하는 +경우 findPOSIX에 정의되어 있지 않다는 것만 지원합니다 . 따라서 find혼자서 선호하는 것이 마음에 들지만 xargs가하는 모든 것을하지는 않습니다. GNU를 고려할 때 멀티 코어를 수행하는 xargs것도 얻을 수 있습니다 -P. xargs상관없이 배울 가치가 있습니다 .
JM 베커

주관적으로 말하면 내 의견은 분명히 다릅니다. 반면에 객관적으로 대답도 정확합니다. 사용 가능한 가장 적은 솔루션 중 하나입니다.
JM Becker

@TechZilla : find가 병렬 호출을 지원하기 시작할 때이 사이트를 다시 방문하는 것을 기억하고 싶습니다. :) 대부분의 경우 복사 / 이동의 경우 디스크 속도가 제한 요인이지만 SSD는 사진을 변경할 수 있습니다. GNU가 아닌 솔루션을 제공하는 것이 좋습니다. 그렇지 않으면 찾기 솔루션은 객관적으로 짧고 간단하며 두 가지 프로세스 만 사용합니다.
사용자가 알 수 없음

0
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;

3
솔루션에 대한 설명을 추가해보십시오.
HalosGhost
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.