찾기를 사용하여 파일을 나열하고 출력에 카운터 값을 포함합니다.

찾기를 사용하여 파일을 나열하고 출력에 카운터 값을 포함합니다.

find성능상의 이유로 많은 수의 파일을 나열하고 각 줄에 카운터를 포함하는 데 사용하고 싶습니다 . 지금까지 내가 가진 것은 다음과 같습니다.

local root_dir="."
local ouptut_file="/tmp/foo.txt"

File_Number=99              ## Initial value

echo "" > "${ouptut_file}"  ## Initialize file to empty

find "$root_dir"   \
    -type f        \
    -depth 2       \
    -name '*.xxx'  \
    -print0        \
| sort -z          \
| xargs -0  printf "DoSomething %5d '%s'\n" $[File_Number++] -- \
> "${ouptut_file}"

이 출력

DoSomething    99 '--'
DoSomething     0 'dirA/dirB/file1.xxx'
DoSomething     0 'dirA/dirB/file2.xxx'
DoSomething     0 'dirA/dirB/file3.xxx'

내가 원하는 건

DoSomething     100 'dirA/dirB/file1.xxx'
DoSomething     101 'dirA/dirB/file2.xxx'
DoSomething     102 'dirA/dirB/file3.xxx'

카운터를 포함하고 출력에서 ​​첫 번째 가짜 라인을 제거하려면 어떻게 해야 합니까?

체계bash: 현재 macOS Ventura 13.0.1에서 사용 중입니다.

답변1

몇 가지 참고사항:

  1. $[...]아주 오래된 산술 확장이다. 오늘날 bash 문서에는 이에 대한 언급조차 없습니다. 대신 사용하십시오 $((...)).
  2. xargs이 명령을 호출할 때마다 새 프로세스가 시작되므로 변수 중 하나를 변경해도 다른 호출에는 영향을 주지 않습니다.
  3. for 는 printf(1)다른 --매개변수와 같습니다. 어떤 일이 발생하면 형식 문자열 요구 사항을 충족하기 위해 매개 변수를 xargs실행 printf "DoSomething %5d '%s'\n" $[File_Number++] dirA/dirB/file1.xxx dirA/dirB/file2.xxx ...하고 반복합니다. printf따라서 각 대체 파일 이름은 실제로 숫자로 처리되어 0출력됩니다.

다음과 같은 것을 사용하고 싶을 수도 있습니다:

find "$root_dir"   \
    -type f        \
    -depth 2       \
    -name '*.xxx'  \
    -print0        \
| sort -z          \
| while read -r -d '' file; do
     printf "DoSomething %5d '%s'\n" $((File_Number++)) "$file"
  done > "${ouptut_file}"

또한 실제로 이것을 사용하여 셸에서 실행되는 명령을 인쇄하는 경우 올바르게 인용하는 %q대신 사용해야 합니다. '%s'에서 help printf:

표준 printf(1) 형식 외에도 %b는 해당 인수에서 백슬래시 이스케이프 시퀀스를 확장하는 것을 의미하고 %q는 쉘 입력으로 재사용할 수 있는 방식으로 인수를 인용하는 것을 의미합니다.

답변2

나는 다음을 사용할 것이다 perl:

find "$root_dir"   \
    -type f        \
    -depth 2       \
    -name '*.xxx'  \
    -print0        \
| sort -z          \
| perl -l -0ne 'printf "something %05d %s\n", $., $_' > "$output_file"

파일을 인용해야 하는 경우 '파일 이름에 포함된 내용과 해당 인용문의 용도에 따라 양쪽에 인용하는 것만으로는 충분하지 않을 수 있습니다. 예를 들어, 일부 셸을 포함한 많은 언어에서는 따옴표 \와 개행 문자가 따옴표 안에 특수하게 남아 있으므로 이스케이프해야 합니다. 어떠한 경우에도 '작은따옴표로 묶인 문자열에 문자를 포함할 수 없습니다.

Bourne과 유사한 쉘에 대한 인용문인 경우 다음 명령을 사용하여 인용할 수 있습니다.

sub shquote {return "'" . ($_[0] =~ s/'/'\\''/gr).  "'"}

그 중 기능이 쉘에서 가장 안전한 인용 형식입니다1. 여기 있습니다:

perl -l -0ne '
  sub shquote {return "'\''" . ($_[0] =~ '"s/'/'\\\\''/gr"').  "'\''"}
  printf "something %05d %s\n", $., shquote($_)'

또는 이러한 인용문을 모두 추적하는 데 어려움을 겪고 있는 경우:

perl -l -0nse '
  sub shquote {return $q . ($_[0] =~ s/$q/$q\\$q$q/gr) . $q}
  printf "something %05d %s\n", $., shquote($_)' -- -q="'"

또한 전역적으로 쓰기 가능한 영역에서 고정된 이름을 가진 파일로 출력하는 것은 보안 관점에서 나쁜 습관입니다. 예를 들어, 누군가가 귀하에게 쓰기 액세스 권한이 있는 일부 민감한 파일과 동일한 이름을 가진 심볼릭 링크를 생성할 수 있습니다. /tmp에 파일을 생성하는 것은 무작위로 생성된 파일 이름 및 O_NOFOLLOW유사한 mktemp작업을 사용하거나 새로 생성된 개인 디렉터리(만들 수 없는 경우 종료, 예를 들어 이미 존재하는 경우 종료)에서만 수행할 수 있습니다 .


1 String::ShellQuote어쨌든 CPAN 모듈보다 더 안전합니다.희귀한 질문.

관련 정보