Làm thế nào để dừng lệnh find sau trận đấu đầu tiên?


131

Có cách nào để buộc findlệnh dừng lại ngay sau khi tìm thấy trận đấu đầu tiên không?


4
TheUnseen: Lý do nó thoát sau năm kết quả khi được dẫn đến đầu -n 5 là vì đầu thoát sau năm kết quả. Khi đầu ra khỏi đường ống sẽ đóng lại và gửi tín hiệu đến chương trình đường ống vào đó để kết thúc. Xin lỗi vì đã không trả lời trực tiếp cho bạn, rõ ràng bạn cần 50 danh tiếng để trả lời.
Ruste

Câu trả lời:


148

Với GNU hoặc FreeBSD find, bạn có thể sử dụng -quitvị ngữ:

find . ... -print -quit

findTương đương NetBSD :

find . ... -print -exit

Nếu tất cả những gì bạn làm là in tên và giả sử tên tệp không chứa ký tự dòng mới, bạn có thể làm:

find . ... -print | head -n 1

Điều đó sẽ không dừng lại findsau trận đấu đầu tiên, nhưng có thể, tùy thuộc vào thời gian và đệm vào trận đấu thứ hai hoặc (nhiều) sau đó. Về cơ bản, findsẽ bị chấm dứt với SIGPIPE khi nó cố gắng xuất một cái gì đó trong khi headđã biến mất vì nó đã đọc và hiển thị dòng đầu vào đầu tiên.

Lưu ý rằng không phải tất cả các shell sẽ chờ findlệnh đó sau khi headđã trả về. Shell Bourne và các triển khai AT & T của ksh(khi không tương tác) và yash(chỉ khi đường ống đó là lệnh cuối cùng trong tập lệnh) sẽ không làm cho nó chạy ở chế độ nền. Nếu bạn muốn thấy hành vi đó trong bất kỳ shell nào, bạn luôn có thể thay đổi ở trên thành:

(find . ... -print &) | head -n 1

Nếu bạn đang làm nhiều hơn là in đường dẫn của các tệp được tìm thấy, bạn có thể thử phương pháp này:

find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;

(thay thế printfbằng bất cứ điều gì bạn sẽ làm với tập tin đó).

Điều đó có tác dụng phụ là findtrả lại trạng thái thoát phản ánh thực tế rằng nó đã bị giết.

Trên thực tế, sử dụng tín hiệu SIGPIPE thay vì SIGTERM ( kill -s PIPEthay vì kill) sẽ khiến một số shell im lặng hơn về cái chết đó (nhưng vẫn sẽ trả về trạng thái thoát khác không).


3
Trong trường hợp bất kỳ ai cũng cần kiểm tra xem có tệp nào khớp với các vị từ hay không, dừng ngay khi tìm thấy, trong Bash và GNU Find bạn có thể làm: if [[ $(find ... -print -quit) ]]; then ...Nó chỉ kiểm tra xem có tìm thấy gì không.
Tobia

@Tobia Tốt hơn là đặt $(…)phần trong dấu ngoặc kép trong trường hợp bạn chỉ sử dụng dấu ngoặc đơn ( [ … ]).
phk

@phk Ngoại trừ tôi không sử dụng dấu ngoặc đơn (vì chúng rất tệ) nên tôi không cần sử dụng dấu ngoặc kép.
Tobia

2
@Tobia, [là một lệnh tiêu chuẩn. Đó không phải là quá nhiều lệnh đó là khủng khiếp nhưng cách vỏ sò giống như Bourne phân tích các dòng lệnh. [[...]]là một cấu trúc ksh có các vấn đề của riêng nó trong các shell khác nhau. Ví dụ, cho đến gần đây [[ $(...) ]]sẽ không hoạt động zsh(bạn cần [[ -n $(...) ]]). Ngoại trừ zsh, bạn cần trích dẫn [[ $a = $b ]], [[ =~ ]]có sự khác biệt không tương thích giữa các lần triển khai và thậm chí giữa các phiên bản cho bash và một số lỗi trong một số. Cá nhân, tôi thích [.
Stéphane Chazelas

...gì .
kyb

11
find . -name something -print -quit

Chấm dứt tìm thấy sau trận đấu đầu tiên sau khi in nó.

Chấm dứt tìm sau một số lượng phù hợp cụ thể và in kết quả:

find . -name something -print | head -n 5

Đáng ngạc nhiên là đủ - bây giờ đầu chấm dứt chuỗi sau 5 trận đấu, mặc dù tôi không biết làm thế nào hoặc tại sao.

Nó rất dễ dàng để kiểm tra. Chỉ cần tìm kiếm trên một root sẽ dẫn đến hàng ngàn, thậm chí có thể nhiều trận đấu hơn trong khi mất ít nhất một phút hoặc hơn. Nhưng khi được dẫn vào "head" "find" sẽ chấm dứt sau khi số lượng dòng được chỉ định trong đầu (đầu mặc định hiển thị 10, sử dụng "head -n" để chỉ định các dòng).

Lưu ý rằng điều này sẽ chấm dứt sau khi "head -n" đạt đến số lượng ký tự dòng mới được chỉ định và do đó, bất kỳ trận đấu nào chứa nhiều ký tự dòng mới sẽ được tính tương ứng.


Tôi cũng đã quan sát thấy 'chương trình này chấm dứt sau khi đầu được thực hiện với hiện tượng đầu ra', nhưng không nhất quán trên các vỏ. Tôi nghĩ rằng điều này xứng đáng với câu hỏi của riêng nó - may mắn thay cho bash, câu trả lời đã có ở hành vi Bash: Head & Tail của StackOverflow với tập lệnh bash . Điều đó cung cấp đủ thông tin để tôi kết luận rằng chương trình chấm dứt hay tiếp tục thực thi trong nền phụ thuộc vào phản ứng của nó với SIGPIPE - giết là mặc định.
hiền nhân

Tôi có nghĩa là 'trên * chương trình * / shells', nhưng rõ ràng unix.stackexchange.com sẽ thích tôi ghi nhật ký này như một nhận xét thứ hai thay vì để tôi chỉnh sửa nhận xét đầu tiên của mình (đây là một quyết định chính sách cụ thể của trang web). Ngoài ra, bây giờ tôi thấy rằng @Ruste đã nhận xét hiệu ứng này ở đầu trang, điều này không giúp tôi ban đầu vì tôi đã đi thẳng vào câu trả lời ...
hiền nhân

2

Đối với mục đích giải trí, đây là một máy phát tìm lười biếng ở Bash. Ví dụ này tạo ra một vòng trên các tệp trong thư mục hiện tại. Đọc tuy nhiên nhiều bạn muốn sau đó kill %+(có thể chỉ 1)

#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT

coproc x while :; do
    find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
    read -r _
    printf '%s\0' "$x"
done
EOF

while
    echo >&${x[1]}
    IFS= read -rd '' -u "$x" 'files[n++]'
do
    printf '%q ' "${files[@]}"
    echo
    sleep .2
done

1

grep cũng trả về nếu được sử dụng với cờ -m, vì vậy với

find stuff | grep -m1 .

nó sẽ trở lại sau dòng đầu tiên được in bằng find.

Sự khác biệt giữa điều này và find stuff -print -quit | head -1là nếu tìm kiếm đủ nhanh, grep có thể không thể dừng quá trình kịp thời (mặc dù không thực sự quan trọng), trong khi nếu tìm kiếm lâu thì sẽ không cần tìm để in nhiều thứ không cần thiết dòng.

thay vào đó, nó hoạt động với findbox, mặc dù vì busybox grep cũng -mkhông thực sự cần thiết

find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;

điều này sẽ tạo ra một thông báo về quá trình tìm kiếm đã nhận được tín hiệu sigterm (thường), nhưng đầu ra này thuộc về shell đang chạy, không phải là lệnh find để nó không gây rối với đầu ra lệnh, nghĩa là các đường ống hoặc chuyển hướng sẽ chỉ xuất ra dòng phù hợp bởi tìm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.