[linux] 리눅스에서 -exec 쉘 기능을 찾으십니까?

find셸에서 정의한 함수를 실행 하는 방법이 있습니까? 예를 들면 다음과 같습니다.

dosomething () {
  echo "doing something with $1"
}
find . -exec dosomething {} \;

그 결과는 다음과 같습니다.

find: dosomething: No such file or directory

얻을 수있는 방법이 있습니까 find의를 -exec볼 수는 dosomething?



답변

쉘만이 쉘 함수를 실행하는 방법을 알고 있으므로 함수를 실행하려면 쉘을 실행해야합니다. 또한로 내보내기를 위해 함수를 표시해야합니다 export -f. 그렇지 않으면 서브 쉘이이를 상속하지 않습니다.

export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;


답변

find . | while read file; do dosomething "$file"; done


답변

위의 Jak의 대답은 훌륭하지만 쉽게 극복 할 수있는 몇 가지 함정이 있습니다.

find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done

줄 바꿈 대신 구분 기호로 null을 사용하므로 줄 바꿈이있는 파일 이름이 작동합니다. 또한 -r파일 이름의 백 슬래시가 작동하지 않으면 백 슬래시 이스케이프를 비활성화 하는 플래그를 사용합니다. 또한 IFS이름의 잠재적 인 후행 공백이 삭제되지 않도록 지 웁니다 .


답변

{}아래와 같이 따옴표를 추가하십시오 .

export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;

find예를 들어 이름에 괄호가있는 파일과 같은 특수 문자로 인해 발생하는 모든 오류를 수정합니다 .


답변

대량 처리 결과

효율성을 높이기 위해 많은 사람들이 xargs결과를 대량으로 처리 하는 데 사용 하지만 매우 위험합니다. 그 때문에 find대량으로 결과를 실행 하는 대체 방법이 도입되었습니다 .

이 방법은 POSIX-의 요구 사항은, 예를 들어 같은 몇 가지주의와 함께 수도 있지만주의 find해야하는 {}명령의 끝에서.

export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +

find는 많은 결과를 단일 호출에 대한 인수로 전달 bash하고 for-loop는 해당 인수를 반복 dosomething하여 각 인수 에 대해 함수 를 실행합니다 .

위의 솔루션은에서 인수를 시작 $1하므로 _(가 나타내는 $0)가 있습니다.

하나씩 결과 처리

같은 방법으로, 나는 받아 들여진 최고 답변이 다음과 같이 수정되어야한다고 생각합니다

export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;

인수가 항상 시작해야하기 때문에,뿐만 아니라 더 제정신 $1뿐만 아니라 사용하여 $0파일 이름에 의해 반환 된 경우 예기치 않은 동작이 발생할 수 있습니다 find쉘에 특별한 의미가 있습니다.


답변

스크립트를 호출하여 각 항목을 인수로 전달하십시오.

#!/bin/bash

if [ ! $1 == "" ] ; then
   echo "doing something with $1"
   exit 0
fi

find . -exec $0 {} \;

exit 0

스크립트를 단독으로 실행하면 찾고자하는 것을 찾고 각 찾기 결과를 인수로 전달하여 자체를 호출합니다. 스크립트를 인수와 함께 실행하면 인수에서 명령을 실행 한 다음 종료됩니다.


답변

현재 디렉토리의 모든 파일에서 주어진 명령을 실행할 bash 함수를 찾고있는 사람들을 위해 위의 답변 중 하나를 컴파일했습니다.

toall(){
    find . -type f | while read file; do "$1" "$file"; done
}

공백이 포함 된 파일 이름으로 구분됩니다 (아래 참조).

예를 들어 다음 기능을 사용하십시오.

world(){
    sed -i 's_hello_world_g' "$1"
}

현재 디렉토리의 모든 파일에서 hello의 모든 인스턴스를 world로 변경하고 싶다고 가정 해보십시오. 난 그럴거야:

toall world

파일 이름의 기호를 안전하게 사용하려면 다음을 사용하십시오.

toall(){
    find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}

(하지만 GNU와 같은 find것을 처리 해야합니다 ).-print0find