*.txt
한 디렉토리에 수백 개의 파일이 있다고 가정합니다. 처음 세 개의 파일을 찾은 *.txt
다음 검색 프로세스를 종료하고 싶습니다.
이 유틸리티를 사용하여 어떻게 이를 달성할 수 있습니까 find
? 매뉴얼 페이지를 잠깐 살펴보았지만 옵션이 표시되지 않았습니다.
답변1
find
출력을 파이프할 수 있습니다 head
.
find . -name '*.txt' | head -n 3
답변2
이 다른 답변몇 가지 결함이 있습니다. 명령은
find . -name '*.txt' | head -n 3
그럼 설명이 나와요댓글 중 하나에[강조 내]:
head
파이프의 왼쪽에서 시작하고 입력을 기다립니다. 그런 다음find
지정된 기준과 일치하는 파일을 시작하고 검색하여 파이프를 통해 출력을 보냅니다.head
요청된 라인 수만큼 수신되어 인쇄 되면 파이프를 닫고 종료됩니다.find
닫힌 파이프를 확인하고 파이프도 종료됩니다.심플하고 우아한,효율적인.
이것은거의진짜.
문제는 find
닫힌 파이프가 쓰기를 시도할 때만 인식된다는 것입니다. 이 경우에는 네 번째 일치 항목이 발견될 때입니다. 하지만 4차전이 없으면 find
진행됩니다. 당신의 껍질이 기다리고 있을 거예요!스크립트에서 이런 일이 발생하면 파이프 출력이 최종이고 아무것도 추가할 수 없다는 것을 이미 알고 있더라도 스크립트는 기다릴 것입니다. 효율성이 낮습니다.
find
이 특정 작업 자체가 빠르게 완료되지만 큰 파일 트리에서 복잡한 검색을 수행하는 경우 다음에 수행할 작업을 불필요하게 지연시켜 이 명령의 효과가 무시될 수 있습니다.
덜 완벽한 솔루션은 다음을 실행하는 것입니다.
( find … & ) | head -n 3
이 방법으로 종료하면 head
쉘이 즉시 계속됩니다. 백그라운드 find
프로세스는 무시되거나(조만간 종료됨) pkill
다른 방식으로 대상이 지정될 수 있습니다.
개념을 증명하기 위해 검색할 수 있습니다 /
. 우리는 단 한 번의 경기만 예상하지만 find
여기저기 알아보고 있기 때문에 시간이 많이 걸릴 수 있습니다.
find / -name / 2>/dev/null | head -n 1
문제가 발견되면 즉시 Ctrl+를 사용하여 종료하세요. C이제 비교해보세요:
pidof find ; ( find / -name / 2>/dev/null & ) | head -n 1 ; pidof find
더 나은 해결책은 다음과 같습니다.
yes | head -n 2 \
| find … -print -exec sh -c '
read dummy || kill -s PIPE "$PPID"
' find-sh \;
노트:
여기서는 일치하는 3개의 파일을 원하지만
head -n 2
(가 아님head -n 3
)을 사용합니다. 세 번째 일치 파일 이후에는read
표준 입력에서 입력을 찾을 수 없으며kill
종료됩니다find
. 를 사용하면 네 번째 파일 이후에 실행됩니다head -n 3
.kill
신호는 입니다
SIGPIPE
.kill -s INT …
또한 작동해야합니다. 가장 간단한 해법()으로SIGPIPE
끝나는 신호이기 때문에 특별히 선택했습니다.find
find … | head -n 3
3개의 파일이 필요한 경우 일치하는 각 파일에 대해 하나씩 실행하는 것은
sh
무시할 수 있습니다. 기억하세요, 목표는find
백그라운드에서 헛되이 실행되는 상황(제가 "완벽하지 않은 솔루션"이라고 부르는 것)을 피하는 것입니다. 운영 체제의 전반적인 성능에 있어서 수명이 짧은 몇 개의 쉘보다 더 중요한 것은 없습니다. " 더 이상 사용되지 않습니다. "find
파일 시스템을 탐색하는 것이 더 좋습니다. 그러나 (최대) 1000개의 파일을 원하고find
더 일찍 파일이 부족할 가능성이 있는 경우(그래서 우리는 아마도 어떤 문제도 피하고 싶지 않을 것입니다) 이러한 쉘은 책임이 있습니다.다음 코드는 프로세스 수를 줄
sh
였지만 결함이 있다고 생각합니다.# flawed, DO NOT USE yes | head -n 999 \ | find … -exec sh -c ' for pathname do printf "%s\\n" "$pathname" read dummy || { kill -s PIPE "$PPID"; exit 0; } done ' find-sh {} +
-print
(쉘 코드 외부에서)를 (쉘 코드 내부에서)로 바꿔야 합니다printf …
. 그 이유는 너무 많은 경로명이-print
앞에-exec sh … {} +
인쇄될 수 있기 때문입니다.잠재적인 문제가 발생합니다. 모든 사람이
printf
별도의 프로세스를 생성하면 이 "최적화"가 의미가 없게 됩니다. 다행스럽게도 거의(?) 모두sh
printf
내장되어 있습니다.그러나 진짜 결점은
exec sh … {} +
경로명을 넘겨주기 전에 가능한 한 많은 경로명을 기다린다는 것입니다sh
. 한편으로 이것이 바로sh
프로세스 수를 줄이는 것입니다. 반면에 1000번째 일치 항목이 대기열에 추가되면find
1001번째 항목에 대한 검색이 계속되고 1001번째 일치 항목이 발견되면 더 많은 항목이 검색될 수 있다는 것이 거의 확실합니다. 이 경우 1001번째 일치가 종료되므로find … | head -n 1000
이 결함이 있는 솔루션은 가장 간단한 솔루션보다 더 나쁘므로 사용하지 마십시오.find … | head -n 3
가장 간단한 해결책()은 인쇄된 경로 이름 중 하나에 개행 문자가 있으면 잘못 계산됩니다. null로 끝나는 문자열을 원할 경우 가장 간단한 해결책은 다음과 같습니다 . 즉, 이 이식 불가능한 옵션을 지원find … -print0 | head -z -n 3
해야 합니다 . 우리의 최적화된 솔루션에서는 쉘 코드 에서는 둘 중 하나 가 필요하지 않습니다.head
-z
head -z
find -print0
printf "%s\\0" "$pathname"
계산은
sh
stdin에 상속된 행을 사용하여 내부적으로 수행 됩니다find
. 일반적으로 에 아무것도 파이프하지 않지만find
일반적으로 계산 이외의 목적으로 파이프할 수 있습니다. 그러면 다른 목적은 우리의 계산 방법과 호환되지 않습니다.yes
휴대가 쉽지 않습니다. 우리의 목적while :; do echo; done
은 휴대용 대안입니다.find-sh
설명은 다음과 같습니다.의 두 번째 sh는 무엇입니까sh -c 'some shell code' sh
?
사용자가 이 솔루션을 구현하는 쉘 기능을 요청했습니다. 여기있어:
findn () (
n="$1"
shift
case "$n" in
'' | *[!0123456789]*) echo >&2 not a valid number;
exit 1;;
esac
[ "$n" -eq 0 ] && exit 0
n="$((n-1))"
while :; do echo; done | head -n "$n" \
| find "$@" -exec sh -c '
read dummy || kill -s PIPE "$PPID"
' find-sh \;
)
첫 번째 매개변수는 원하는 최대 일치 수이며 나머지는 처리됩니다 find
. 노트:
그 이유
case
는 다음과 같습니다.쉘 산술 평가에서 정리되지 않은 데이터 사용의 보안 영향.런타임에
find
함수가 추가되므로-exec …
암시적인-print
. 결과를 인쇄하려면-print
이를 명시적으로 지정하십시오.
사용 예:
findn 2 / -name bin -print 2>/dev/null
답변3
find
많은 사람들에게 효과가 있을 수 있는 이것이 없는 해결책은 fd
Rust로 작성된 찾기 같은 도구를 사용하는 것입니다. (fd는 간단하고 빠르며 사용자 친화적인 대안입니다.)
fd --glob '*.txt' /path/to/search --max-results $n
답변4
4.4+ 및 GNU 도구를 사용하여 bash
세 번째 파일을 찾은 후 일찍 종료하려면 다음을 수행할 수 있습니다.
n=3
readarray -td '' first_3_files < <(
(
echo "$BASHPID"
LC_ALL=C exec stdbuf -o0 find . -name '*.txt' -type f -print0
) | {
IFS= read -r pid
head -zn "$n"
kill -s PIPE "$pid"
}
)
echo "The first $n files are:"
printf ' - %s\n' "${first_3_files[@]}"
stdbuf -o0
find
검색을 계속하고 네 번째 파일 경로를 찾아 인쇄할 때만 SIGPIPE를 수신하는 대신 출력 버퍼링을 중지하고 반환하자마자 SIGPIPE 신호를 보냅니다 .find
head -zn 3
find
또는 GNU 조건자를 사용하는 또 다른 GNU 특정 find
방법 -quit
:
n=3
readarray -td '' first_3_files < <(
seq "$((n - 1))" | LC_ALL=C find . -name '*.txt' -type f -print0 \
! -exec read iteration ';' -quit)
( 시스템에 독립 실행형 유틸리티가 없는 경우 read
이 유틸리티를 사용하십시오 -exec sh -c 'read iteration' ';'
. read
있는 시스템에는 내장 프로그램 주변의 쉘 스크립트 래퍼로 구현되었을 수 있습니다 read
.)
를 사용하면 zsh
다음을 수행할 수 있습니다.
first_3_files=( **/*.txt(ND.Y3) )