find -exec 명령 사용 {} + 명령 호출 횟수

find -exec 명령 사용 {} + 명령 호출 횟수

맨페이지 상태 찾기:

   -exec command {} +
          This variant of the -exec action runs the specified command on the selected files,
          but the command line is built by appending each selected file name at the end;
          the total number of invocations of the  command  will  be
          much  less than the number of matched files.

find항상 이것이 한 번만 실행될 것이라고 생각했습니다 command. 명령이 몇 번 호출되었는지 알 수 있는 방법이 있습니까?

내 생각에 이것이 한 번만 발생했다면 command처리하기에는 너무 큰 매개변수 목록을 작성할 위험이 있기 때문에 이것은 중요합니다. 그러나 find가 호출을 분할하게 되면(예: parallel), 이 상황은 다음과 같습니다. 완화되다.

답변1

사용되는 버퍼는 find버전에 따라 다릅니다. 여기에 제공한 SuSE 상자의 크기는 약 256Kb인 것 같습니다.

따라서 "명령"이 호출된 횟수를 계산하려면 발견된 각 파일 경로의 길이를 알아야 합니다. 그러면 이는 (대략) 모든 경로 길이의 합계에 구분 공백에 1을 더하고 명령 자체를 뺀 값이 됩니다. 버퍼 영역 크기로 나눈 값입니다.

예를 들어, 평균 경로 길이가 200바이트인 20,000개의 파일을 찾았습니다. 이는 4,020,000바이트를 256Kb로 나눈 값이 15.33이므로 약 16번의 호출이 필요합니다.

두 번의 연속 호출 사이에 파일 경로를 파괴하지 않아도 된다는 점을 고려하면 정확한 계산은 조금 더 복잡하지만 대략적인 수치를 얻을 수 있습니다.

바라보다여기한 스레드(소스 코드 포함)의 경우 크기는 32Kb로 보고되었으며 불필요하게 낮은 것으로 간주됩니다.find 시스템 제한을 사용하십시오. 나는 실험하지 않았습니다) coreutils버전은 다음과 같이 추론됩니다.128KB인 것보다 4배 더 많은 것 같습니다..

답변2

제한은 find(1)버퍼와 명령이 처리하는 내용(커널에 따라 다름)에 따라 달라집니다. 마지막 비율이 성능에 매우 중요한 것이 아니라면 시스템의 기본 설정은 괜찮을 것입니다.

성능이 걱정된다면 고려해보세요모두이 작업을 수행하는 시스템 및측정하다병목 현상은 어디에 있습니까? 당신은 그럴 가능성이 있습니다매우당신이 발견한 것에 놀라십시오. Bentley는 뛰어난 Writing Efficient Programs(Prentice-Hall, 1982)(슬프게도 절판)에서 본질적으로 사용되지 않고 치명적인 버그가 있는 프로그램을 초래한 주의 깊은 "최적화"에 대한 여러 이야기를 공유합니다. 코드는 "더 빠르거나" 프로그램의 유휴 상태를 최적화합니다. 고리. 운영 체제를 측정한 결과 컴퓨터 시간의 상당 부분을 차지하는 것으로 나타났습니다. 사람들은악명 높게비효율성이 어디에 있는지 추측하는 데 능숙하지 않습니다. 또한 더 높은 수준(시스템 아키텍처, 전체 조직, 알고리즘 및 데이터 구조)에 대한 작업은 세부적인 작업보다 더 가치가 있습니다.

답변3

예비 설명: 매뉴얼과 질문은 command명령을 나타내는 데 사용되지만 POSIX는 문자 그대로 이름이 지정된 유틸리티를 정의하므로command, 내 대답은 을 사용합니다 cmmnd.


cmmnd실제로 실행 하고 호출 횟수만 세고 싶다면 (주의하세요)뒤쪽에 finddone) 그런 다음 계산할 수 있는 작업(예: stderr로 인쇄, 로그 파일로 인쇄, 경고음)을 수행하는 래퍼를 만들고 마지막으로 를 실행합니다 cmmnd.

#!/bin/sh
echo "invoking cmmnd" >&2
cmmnd "$@"

그런 다음 inside wrapper대신 에 를 사용하십시오 .cmmndfind

너무 길지 않은 명령은 생성할 때 find사용되며 /absolute/path/to/wrapper래퍼는 를 사용합니다 /absolute/path/to/cmmnd. 후자가 더 길면 이를 포함하는 일부 명령줄이 너무 길어질 수 있습니다. 따라서 이 접근 방식은 우리가 원하는 것만큼 간단하지 않습니다. find예를 들어 문자 그대로 추가 슬래시를 제공하여 이전 경로를 확장 할 수 있습니다 /absolute/path/to/////wrapper.


이제 나는 당신이 번호를 알고 싶어한다고 가정합니다앞으로당신은 달리기로 결정했습니다 cmmnd. 이와 같은 경우처럼 두 번 호출하는 것은 (어떤 이유로든) 나쁜 일이며 한 번만 실행되도록 cmmnd하고 싶습니다 .find

cmmnd "$@"위에 주석 처리된 래퍼를 사용하는 것이 가능합니다. 다음은 몇 가지 다른 아이디어입니다(결국 크게 다르지는 않지만).

당신이 이것을 하고 싶다고 가정해 봅시다:

find . -exec cmmnd … {} +

( 상수 매개변수를 나타냄) cmmnd실제 절대 경로가 무엇인지 알아보세요 . 예를 들어 /bin/cmmnd. 그런 다음 다음과 같이 실행하십시오.

find . -exec /aaa/zzzzz … {} +

/aaa/zzzzz와 길이가 같은 이름을 가진 존재하지 않는 명령은 어디에 있습니까 /bin/cmmnd? 이제 find명령줄은 /aaa/zzzzz명령줄과 동일한 길이로 작성됩니다 /bin/cmmnd. 당신은 얻을 것이다

find: '/aaa/zzzzz': No such file or directory

한 번 이상. 원하는 숫자를 얻으려면 숫자를 세어보세요. 이 간단한 방법은 다음과 같습니다.

find . -exec /aaa/zzzzz … {} + 2>&1 | wc -l

find가능한 최고는 아니다반품예를 들어 permission denied발견된 일부 파일을 인쇄하십시오. 그러나 /aaa/zzzzz한 줄(빈 줄도 가능)만 인쇄하는 유효한 실행 파일을 만드는 경우 다음과 같이 작동합니다.

find . -exec /aaa/zzzzz … {} + | wc -l

또 다른 개선점은 도구 이름을 /a( 대신 ) 지정하고 필요한 기간에 따라 도구 등으로 부르는 /aaa/zzzzz것 입니다. 예://///a/////////////////a

find . -exec /////////a … {} + | wc -l

완전성을 위해 a다음과 같이 보일 수 있습니다.

#!/bin/sh
echo

우리의 래퍼가 그렇지 않은 것과 거의 비슷하지만 cmmnd "$@"표준 출력을 사용합니다.

노트:

  • 정확한 문자 수는 /중요하지 않습니다. 몇몇 사람의 실수로는 결과가 바뀌지 않는다철저히. 필요하다면추정결과적으로, ///////////a거기로 이어지는 경로가 cmmnd비정상적으로 길지 않는 한 맹목적으로 왼쪽과 오른쪽을 사용할 수 있습니다. 정확한 사용법에 따라 /a하한이 제공됩니다.

  • 실제로는 다른 테스트가 선행되는 경우가 많습니다 -exec cmmnd … {} +. 등 cmmnd으로 교체해 /////////a도 다른 테스트는 계속 실행됩니다. -exec처음에 경로 이름의 경로를 결정하므로 이를 무시해서는 안 됩니다 . 그러나 테스트가 무언가를 수행하거나 변경 cmmnd하는 경우 이러한 .

    -delete -exec cmmnd … {} +예를 들어 삭제된 파일에 대한 보고서를 생성 하는 파일 삭제 를 사용할 수 있습니다 cmmnd. 이 경우 를 사용하면 /////////a파일이 삭제됩니다.아니요보고서를 생성합니다. 그러므로 행동하기 전에 생각하십시오.

  • 테스트/작업/이 -exec /////////a … {} +stdout에 아무것도 인쇄하지 않는지 확인하십시오. 아니면 /a다른 채널을 이용하세요.

  • 그렇지 않더라도 주어진 디렉토리 트리를 처리하고 (다른) 테스트를 수행하는 데 시간이 걸릴 수 있습니다 cmmnd.

답변4

음, 표준 텍스트는 다음과 같이 말합니다.

두 개 이상의 경로 이름 집합의 크기는 유틸리티 실행으로 인해 시스템의 {ARG_MAX} 제한이 초과되지 않도록 제한되어야 합니다.

따라서 실행하기에는 너무 큰 매개변수 목록을 작성해서는 안 됩니다. 이는 그러한 기능의 요점을 무효화합니다.

수행하는 호출 수는 구현에 따라 다르므로 크게 신경쓰지 않아도 됩니다. 표준에서는 -exec동일한 절에 대한 호출이 중복되지 않을 것이라고 약속합니다. 이는 외부 상태로 무언가를 실행하는 경우 정확성과 관련될 수 있습니다.

그러나 Linux에서 명령줄 매개변수의 실제 최대 크기는 스택 크기를 기반으로 하며 간접 참조를 사용하여 변경할 수 있습니다 ulimit -s. 예를 들어 xargs, find내 Debian 및 Ubuntu 제품은 실제로 런타임에 제한을 확인하지 않으므로 이론적으로 문제가 발생할 수 있습니다.

$ mkdir bar
$ touch bar/{00000..99999}
$ ulimit -Ss 512
$ getconf ARG_MAX
131072
$ find bar -type f -exec sh ./args.sh {} +
find: ‘sh’: Argument list too long
find: ‘sh’: Argument list too long
...

그러나 기본값은 ulimit -s8192이므로 매우 제한된 시스템을 제외하고는 해당 문제가 발생할 가능성이 없습니다.

관련 정보