find -exec 호출에서 사용자 정의 함수 실행


25

Solaris 10을 사용하고 있으며 ksh (88), bash (3.00) 및 zsh (4.2.1)로 다음을 테스트했습니다.

다음 코드는 결과를 생성하지 않습니다.

function foo {
    echo "Hello World"
}

find somedir -exec foo \;

찾기는 여러 파일과 일치하며 (로 대체 -exec ...하여 -print표시됨)이 함수는 호출 외부에서 find호출 될 때 완벽하게 작동합니다 .

man find페이지에 대한 내용은 다음과 같습니다 -exec.

 -exec 명령 실행 된 명령이 a를 반환하면 true
                     종료 상태로 0 값. 끝
                     이스케이프 처리 된 명령은 문장 부호를 사용해야합니다.
                     세미콜론 (;). 명령 인수 {}는
                     현재 경로 이름으로 대체됩니다. 만약
                     -exec의 마지막 인수는 {}이고
                     세미콜론 (;) 대신 +를 지정하십시오.
                     명령이 더 적은 횟수로 호출됩니다.
                     {}는 경로 이름 그룹으로 대체되었습니다. 만약
                     명령을 호출하면
                     종료 상태로 0이 아닌 값, 찾기
                     0이 아닌 종료 상태를 반환합니다.

아마 다음과 같은 일을 할 수 있습니다.

for f in $(find somedir); do
    foo
done

그러나 필드 구분 기호 문제를 처리하는 것이 두렵습니다.

호출에서 쉘 함수를 호출 할 수 있습니까 (동일한 스크립트에 정의되어 있고, 범위 지정 문제를 해결하지 find ... -exec ...않겠습니까)?

나는 모두 그것을 시도 /usr/bin/find/bin/find같은 결과를 얻었다.


선언 한 후에 함수를 내보내려고 했습니까? export -f foo
h3rrmiller

2
함수를 외부 스크립트로 만들어서 넣어야합니다 PATH. 또는 비트를 사용 sh -c '...'하여 함수를 정의하고 실행하십시오 .... 함수와 스크립트차이점 을 이해하는 데 도움이 될 수 있습니다 .
jw013

답변:


27

A function는 쉘에 로컬이므로 쉘 find -exec을 생성하고 사용하기 전에 해당 함수를 해당 쉘에 정의해야합니다. 다음과 같은 것 :

find ... -exec ksh -c '
  function foo {
    echo blan: "$@"
  }
  foo "$@"' ksh {} +

bash를 사용하여 환경을 통해 함수를 내보낼 export -f수 있으므로 bash에서 다음을 수행 할 수 있습니다.

foo() { ...; }
export -f foo
find ... -exec bash -c 'foo "$@"' bash {} +

ksh88typeset -fx내보내기 기능 (안 환경을 통해)에 있지만은 그녀 - 뱅 덜 의해 실행되는 스크립트에서 사용할 수있는 ksh너무하지 ksh -c.

다른 옵션은 다음과 같습니다.

find ... -exec ksh -c "
  $(typeset -f foo)"'
  foo "$@"' ksh {} +

즉 , 인라인 스크립트 내에서 함수 typeset -f정의를 덤프하는 데 사용 foo하십시오. foo다른 함수를 사용 하는 경우 해당 함수도 덤프해야합니다.


2
ksh또는 명령 bash에 두 번의 발생이 있는지 설명 할 수 있습니까 -exec? 첫 번째는 이해하지만 두 번째는 이해하지 못합니다.
다니엘 쿨만

6
@danielkullmann에서가 bash -c 'some-code' a b c, $0있다 a, $1있다 b... 그래서 당신이 원하는 경우 $@a, b, c당신은 이전에 뭔가를 삽입해야합니다. $0오류 메시지를 표시 할 때도 사용 되기 때문에 셸 이름 또는 해당 컨텍스트에 적합한 이름을 사용하는 것이 좋습니다.
Stéphane Chazelas

@ StéphaneChazelas, 좋은 답변 주셔서 감사합니다.
User9102d82

5

항상 적용 할 수있는 것은 아니지만 간단한 해결책입니다. globstar옵션을 설정하십시오 ( set -o globstarksh93 shopt -s globstar에서 bash ≥4; 기본적으로 zsh에서 켜져 있습니다). 그런 다음 **/현재 디렉토리와 해당 서브 디렉토리를 재귀 적으로 일치시키는 데 사용 하십시오.

예를 들어, 대신 find . -name '*.txt' -exec somecommand {} \;, 당신은 실행할 수 있습니다

for x in **/*.txt; do somecommand "$x"; done

대신에 find . -type d -exec somecommand {} \;, 당신은 실행할 수 있습니다

for d in **/*/; do somecommand "$d"; done

대신에 find . -newer somefile -exec somecommand {} \;, 당신은 실행할 수 있습니다

for x in **/*; do
  [[ $x -nt somefile ]] || continue
  somecommand "$x"
done

**/당신을 위해 일을하지 않습니다 (쉘은 그것이있다, 또는 당신이 필요하기 때문에하지 않기 때문에 find쉘 아날로그가없는 옵션), 에서 함수를 정의 find -exec인수 .


사용중인 globstarksh ( ksh88) 버전 에서 옵션 을 찾을 수 없습니다 .
rahmu

@rahmu 사실, 그것은 ksh93의 새로운 기능입니다. Solaris 10에 어딘가에 ksh93이 없습니까?
Gilles 'SO- 악마 그만'10

이 블로그 게시물 에 따르면 ksh93은 Bourne Shell과 ksh88을 대체하기 위해 Solaris 11에 도입되었습니다 ...
rahmu

@rahmu. Solaris는 ksh93을 잠시 동안 dtksh(일부 X11 확장명을 가진 ksh93) 가지고 있었지만, 구 버전이며 CDE가 선택적인 선택적 패키지의 일부일 수 있습니다.
Stéphane Chazelas

재귀 globbing은 점 파일을 find제외하고 dotdirs로 내려 가지 않고 파일 목록을 정렬한다는 점과 다릅니다 (둘 다 globbing 한정자를 통해 zsh의 주소가 될 수 있음). 또한와 **/*는 대조적으로 ./**/*, 파일 이름으로 시작할 수 있습니다 -.
Stéphane Chazelas

4

\ 0을 구분 기호로 사용하고 다음과 같이 생성 된 명령에서 현재 프로세스로 파일 이름을 읽습니다.

foo() {
  printf "Hello {%s}\n" "$1"
}

while read -d '' filename; do
  foo "${filename}" </dev/null
done < <(find . -maxdepth 2 -type f -print0)

무슨 일이야?

  • read -d '' 다음 \ 0 바이트까지 읽으므로 파일 이름의 이상한 문자에 대해 걱정할 필요가 없습니다.
  • 마찬가지로, -print0\ n 대신 \ 0을 사용하여 생성 된 각 파일 이름을 종료하십시오.
  • cmd2 < <(cmd1)cmd1 | cmd2cmd2가 서브 쉘이 아닌 기본 쉘에서 실행된다는 점 을 제외하고 는 동일 합니다.
  • /dev/null파이프에서 실수로 읽지 않도록 foo 호출이 리디렉션됩니다 .
  • $filename 셸은 공백이 포함 된 파일 이름을 분할하지 않습니다.

이제 read -d<(...)zsh을, 배쉬 및 KSH 93u에 있지만, 나는 확실히에 대한 이전 KSH 버전 아니에요.


4

스크립트에서 생성 된 자식 프로세스가 미리 정의 된 셸 함수를 사용하도록하려면 export -f <function>

참고 : export -fbash 특정

쉘만 기능을 실행할 수 있기 때문에 :

find / -exec /bin/bash -c 'function "$1"' bash {} \;

편집 : 기본적으로 스크립트는 다음과 유사해야합니다.

#!/bin/bash
function foo() { do something; }
export -f foo
find somedir -exec /bin/bash -c 'foo "$0"' {} \;

1
export -f의 구문 오류이며 ksh의 함수 정의를의 화면에 인쇄합니다 zsh. 모든 년 ksh, zsh그리고 bash, 그것은 문제가 해결되지 않습니다.
rahmu

1
find / -exec /bin/bash -c 'function' \;
h3rrmiller

이제는 작동하지만 bash. 고맙습니다!
rahmu

4
{}쉘 코드에 포함시키지 마십시오 ! 이는 파일 이름이 쉘 코드로 해석되어 매우 위험하다는 것을 의미합니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.