find exec에서 for 루프 사용

find exec에서 for 루프 사용
 -> find  .. -name bin  -exec  for file in {}/* ; do echo $file ; done  \;

   -bash: syntax error near unexpected token `do'

이 명령의 올바른 구문은 무엇입니까?

답변1

for여러 문(예: -loop )을 인수로 사용하려면 명시적으로 셸을 호출 -exec해야 합니다 bash. 예:

find .. -name bin -exec bash -c 'for file in "$1"/* ; do echo "$file" ; done' none {}  \;

공백이나 기타 적대적인 문자가 포함된 파일 이름에도 안전합니다.

bash -c작동 원리

bash는 다음 형식의 명령을 사용하여 호출할 수 있습니다.

bash -c some_complex_commands arg0 arg1 arg2 ...

이 경우 bash는 string에 있는 모든 것을 실행합니다 some_complex_commands. 이 명령은 일반 쉘을 사용하여 사용할 수 있습니다위치 매개변수. arg0위 명령 뒤의 첫 번째 인수는 에 할당되고 $0, 두 번째 인수는 에 할당되고 $1, 세 번째 인수는 에 할당되는 $2식입니다.

일반 셸 스크립트를 실행할 때 $0이는 스크립트 이름과 $1명령줄에 나타나는 첫 번째 인수입니다. 이 전통을 유지하면서 스크립트에 적절한 이름이 없기 때문에 파일 이름( find 표기법) bash -c을 할당하도록 명령이 작성 되었습니다 . {}$1none$0

답변2

원하는 것과 반대되는 결과를 얻고 있는 것 같습니다. 이 시도:

for f in `find .. -name bin`
do
echo $f
done

답변3

다음과 같이 기본 요소를 사용하여 의사 코드의 출력을 근사화할 수 있습니다 find.

find .. -path \*/bin/\* ! -name .\* 

...로 시작하지 않는 이름만 인쇄해야 합니다. 해당 이름은 어느 정도 상위 디렉터리에 뿌리를 두고 있으며, 더 큰 범위는 이라는 디렉터리에 뿌리를 두고 있습니다 /bin.

일반적으로 하위 프로세스에서 루프를 실행하는 다양한 실제 목적을 생각할 수 있지만 find -exec전달된 인수에 대해 shelld glob을 수행하는 것은 가능하지 않다고 생각합니다 find. 의사코드와 동일한 작업을 수행하려면 printf- 이를 사용하면 인수를 문자 그대로 출력으로 변환할 수 있으므로 다음과 같이 할 수 있습니다.

find .. -type d -name bin -exec sh -c '
    printf %s\\n "$0/"*' {} \;

...루핑 없이 인쇄 및 와일드카드를 수행합니다 for. 하지만 이 명령과 예제 명령의 한 가지 차이점은 이름과 일치하는 결과에 대한 사양과 유형이 없으면 -type d결과는 d bin가 된다는 것입니다 . 따라서 표준 출력에 기록되는 echo많은 내용을 볼 가능성이 높습니다. bin/*. 물론, 가 있더라도 해결 -type d된다는 보장은 없습니다 *. 빈 디렉터리나 .파일만 포함된 디렉터리는 일치하는 항목을 렌더링하지 않으므로 이를 볼 수 있습니다.

{} \;또한 이 예제는 다른 방법보다 훨씬 느릴 수 있는 기본 형식을 사용하므로 의사코드라는 점에 유의하세요 . printf예를 들어 다음과 같이 작업을 다시 시도 합니다 .

find .. -type d -name bin -exec sh -c '
    for d do printf %s\\n "$d/"*; done' -- {} +

...이것은 여전히 ​​빈 glob 상황의 위험이 있지만 -exec한 번에 하나의 쉘을 일치시키는 대신 실행 시 다른 프로세스에 합리적으로 전달할 수 있는 만큼의 인수를 수집하고 인수를 위치 매개변수 배열에 전달합니다. - 루프 sh에서 "$@"사용할 수 있습니다 for d do printf....

이제 단순히 결과를 인쇄하는 것(문장 내에서 반복할 때 일반적으로 유용하다고 생각하는 것) 이외의 다른 작업을 수행하려는 경우 이전 예제 -exec로 돌아가서 다음과 같은 것과 결합할 수 있습니다.-path-exec

find .. -path \*/bin/\* -exec sh -c '
    for arg do : something with "$arg"
done' -- {} +

관련 정보