"찾기" 출력에서 ​​심볼릭 링크가 아닌 파일 수 계산

"찾기" 출력에서 ​​심볼릭 링크가 아닌 파일 수 계산

Locate 명령을 통해 전달된 non-symlink 파일 수를 계산하려고 합니다. 나는 여러 가지 옵션을 시도했는데 이것이 가장 유망하다고 생각합니다.

locate -r "$PWD.*\.c$" | xargs -0 -I{} test -f {} && echo "regular file" | wc -l

문제는 그것이 작동하지 않는다는 것입니다.

총 30개의 파일이 있는데 그 중 1개는 심볼릭 링크 wc -l이므로 29.

나는 xargs그것을 완전히 건너 뛰려고했습니다.

locate -r "$PWD.*\.c$" | test -f && echo "regular file" | wc -l

나는 노력했다아니요심볼릭 링크:

locate -r "$PWD.*\.c$" | test ! -h && echo "regular file" | wc -l
locate -r "$PWD.*\.c$" | test ! -L && echo "regular file" | wc -l

locate출력을 파이프하고 일반 파일 수와 심볼릭 링크 수를 계산하는 가장 효율적인 방법은 무엇입니까?


댓글에 답장하기

어떤 사람들은 연출 을 좋아합니다 locate. find불가지론자였으면 좋겠지만 locate가능하면 사용하고 싶습니다. 댓글이 게시되었으며 질문에 답변하고 싶습니다.

  • updatedb첫 번째 실행에는 30초가 걸리지만 후속 실행에는 4초만 걸립니다. 5분마다 달리는 것은 cron하루에 한 번이라는 기본값에 대한 무모한 반응입니다. 하지만 노트북의 CPU 사용량은 10~20%에 불과하고 렉도 전혀 없습니다.
  • 캐시를 삭제한 후 find파일 하나를 찾는데 1분 9초가 소요됩니다 .
  • 캐시를 삭제한 후 locate동일한 파일을 찾는데 1초가 소요됩니다 .

다음은 시스템에 복제할 수 있는 몇 가지 벤치마크입니다.

$ sudo -i
# sync; echo 1 > /proc/sys/vm/drop_caches; sync; echo 2 > /proc/sys/vm/drop_caches; sync; echo 3 > /proc/sys/vm/drop_caches; exit
logout

$ time locate .hidden.c | wc -l
1

real    0m0.790s
user    0m0.758s
sys     0m0.028s

$ sudo -i
# sync; echo 1 > /proc/sys/vm/drop_caches; sync; echo 2 > /proc/sys/vm/drop_caches; sync; echo 3 > /proc/sys/vm/drop_caches; exit
logout

$ time find / iname '.hidden.c'  2>/dev/null | wc -l
1888926

real    1m9.044s
user    0m5.158s
sys     0m15.004s

$ sudo -i
# sync; echo 1 > /proc/sys/vm/drop_caches; sync; echo 2 > /proc/sys/vm/drop_caches; sync; echo 3 > /proc/sys/vm/drop_caches; exit
logout

$ time sudo updatedb

real    0m29.323s
user    0m1.267s
sys     0m4.784s

$ time sudo updatedb

real    0m3.592s
user    0m0.479s
sys     0m1.211s

find의심할 여지 없이 그보다 더 강력 locate하지만 locate몇 배 더 빠르고 구문도 기억하기 더 쉽습니다.

실제로, 오늘 생성된 파일을 포함하거나 오늘 삭제된 파일을 제외하도록 데이터베이스를 업데이트하려면 명령 에 대한 sudo updatedb인수를 한 번에 실행하거나 전달해야 한다는 것을 기억해야 합니다 . 하지만 반면에 매개변수를 전달하는 것을 기억해야 합니다 .-ulocatefind2>/dev/null

첫째로 내 노트북이 제대로 작동하지 않고 둘째로 게으르기 때문에 5분마다 cron실행하기 로 결정했습니다 .updatedb

답변1

이 명령은 닫힙니다.

locate -r "$PWD.*\.c$" | xargs -0 -I{} test -f {} && echo "regular file" | wc -l

질문:

  • xargs와 함께 nul로 구분된 입력을 사용하지만 locatenul로 구분된 출력은 제공하지 않습니다.
  • 단일 파이프라인이 아닌 전체 파이프라인에 대해 실행 && echo됩니다 .locate | xargstest

노력하다:

locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test -f "$1" && echo "regular file"' _  {} | wc -l
  • locate다음을 사용하여 Null로 구분된 출력을 활성화합니다.-0
  • testand 와 결합됨 ( 각 호출이 여러 파일을 처리하도록 echo매개변수 루프로 개선될 수 있음 )sh -csh

에는 여전히 정규식 연산자가 있습니다 $PWD.

답변2

그리고 zsh:

set -o extendedglob # best in ~/.zshrc
c_regular_files=(
  ${(0)^"$(locate -0 "${${PWD%/}//(#m)[]\\*?]/\\$MATCH}/*.c")"}(N.)
)
echo there are at least $#c_regular_files regular files whose name ends in .c
  • for 에서 [, 및 ?를 이스케이프해야 하며 와일드카드 연산자로 해석하지 않아야 합니다( 파일 이름에 common , 을 포함하여 더 많은 연산자가 있는 정규 표현식의 경우 더욱 나쁩니다).\*$PWDlocate-r.
  • $PWD==는 /특별히 처리되어야 합니다. $PWD대신 을 사용하면 이를 ${PWD%/}실행 locate -0 "//*.c"하고 아무것도 반환하지 않습니다.
  • -0파일은 NUL로 구분됩니다(파일 경로에 줄바꿈이 허용되므로 줄바꿈은 효과가 없습니다).
  • .이다정기적인문서. 대조적으로 [ -f, 일반 파일에 대한 심볼릭 링크는 제외됩니다. Symlink가 아닌 모든 .c파일(디렉토리, fifo, 소켓 등과 같은 다른 유형의 파일 허용)을 원하는 .경우 ^@.

그럼에도 불구하고 locate반환된 목록은 locate데이터베이스가 마지막으로 업데이트된 시간을 기반으로 하므로 현재 현실을 반영하지 않을 수 있습니다.

답변3

구문 분석 대신 locate(깨지기 쉬우며 데이터베이스가 마지막으로 업데이트된 이후 변경된 항목 또는 사용할 수 없는 항목을 놓칠 수 있음)모두사용자), find.

.c다음 명령은 현재 디렉토리에서 모든 일반 파일(심볼릭 링크 아님)에 대한 파일을 찾습니다 .

find . -type f -name '*.c'

주어진 디렉토리 구조

.
|-- file-a.c
|-- file-b.c
|-- file-c.c
|-- file-d.c
|-- link-b.c -> file-b.c
`-- link-d.c -> file-d.c

이 반환됩니다

./file-a.c
./file-b.c
./file-c.c
./file-d.c

세어보세요:

find . -type f -name '*.c' | wc -l

또는 파일 이름에 개행 문자가 포함된 경우

find .//. -name '*.c' -type f | grep -c //

심볼릭 링크로 동일한 작업을 수행하려면 -type f로 변경 -type l.

답변4

GNU Parallel을 사용하면 다음과 같습니다:

locate -r "$PWD.*\.c$" | parallel 'test -f {} && echo "regular file"' | wc -l

보시다시피 원래 시도와 매우 가깝습니다.

적중 수가 100개 미만인 경우 GNU Parallel을 사용하여 실패한 작업 수를 최대 100개로 설정할 수 있습니다(확장되지 않음).

ls  *txt | parallel \! test -f {}
echo $?

더 빨리 필요한 경우:

locate -r "$PWD.*\.c$" |
  perl -ne 'chomp; -l $_ or $s+= -f $_; END{print "$s\n"}'

또는 조합:

locate -r "$PWD.*\.c$" |
  parallel --block 10k --pipe -q perl -ne 'chomp; -l $_ or $s+= -f $_; END{print "$s\n"}' |
  awk '{s+=$1} END {print s}'

관련 정보