Câu trả lời:
Đây là một giải pháp POSIX khá dễ hiểu:
find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;
Như trong câu trả lời của Stephane , hãy loại bỏ echo
khi hài lòng với những gì sẽ bị xóa.
Dấu chấm .
đại diện cho thư mục hiện tại. find
tìm thấy các tập tin và thư mục đệ quy bên trong .
, và có thể làm mọi thứ với chúng.
-type
là một trong những find
's bầu cử sơ bộ ; đó là một bài kiểm tra sẽ được thực hiện cho từng tệp và thư mục được tìm thấy đệ quy (bên trong .
) và phần còn lại của các nguyên tắc trên dòng chỉ được đánh giá nếu kết quả này là "đúng".
Trong trường hợp cụ thể này, chúng tôi chỉ tiếp tục nếu chúng tôi đang xử lý một tệp thông thường , không phải thư mục hoặc thứ gì khác (ví dụ: thiết bị khối.)
Chính -exec
(của find
) gọi một lệnh bên ngoài và chỉ tiến hành chính tiếp theo nếu lệnh bên ngoài thoát thành công (trạng thái thoát của "0"). Tên {}
được thay thế bằng tên tệp được "xem xét" bởi find
lệnh. Vì vậy, -exec
cuộc gọi đầu tiên tương đương với lệnh shell sau, lần lượt được thực hiện cho từng tệp:
awk -v x=10 'NR==x{exit 1}' ./somefilename
Awk là toàn bộ ngôn ngữ, được thiết kế để xử lý các tệp văn bản được phân tách như CSV. Các điều kiện và lệnh Awk (được chứa giữa các dấu ngoặc đơn và bắt đầu bằng các chữ cái NR
) được thực thi cho mỗi dòng của tệp văn bản. (Lặp lại ngầm định.)
Để tìm hiểu Awk đầy đủ, tôi rất khuyến khích Hướng dẫn Grymoire , nhưng tôi sẽ giải thích các tính năng Awk được sử dụng trong lệnh trên.
Các -v
lá cờ để AWK cho phép chúng ta thiết lập một biến AWK (một lần) trước khi các lệnh AWK được thực hiện (đối với mỗi dòng của tập tin.) Trong trường hợp này, chúng tôi thiết lập x
để 10
.
NR
là một biến Awk đặc biệt đề cập đến " số N của R hiện tại ecord ." Nói cách khác, đó là số dòng chúng ta đang xem xét trong bất kỳ đoạn cụ thể nào đi qua vòng lặp.
(Lưu ý rằng nó là có thể, mặc dù không bình thường, sử dụng một "khác nhau R ecord S eparator" hơn so với mặc định của một ký tự xuống dòng, bởi khung cảnh RS
. Dưới đây là một ví dụ về chơi với dải phân cách kỷ lục. )
Các tập lệnh Awk nói chung bao gồm các điều kiện (bên ngoài dấu ngoặc nhọn) kết hợp với các hành động (bên trong dấu ngoặc nhọn.) Có thể có các điều kiện ghép và hành động ghép và có một điều kiện mặc định (đúng) và hành động mặc định (in), nhưng chúng ta cần Không bận tâm với những điều đó.
Điều kiện ở đây là "Đây có phải là dòng thứ 10 không?" Nếu đây là trường hợp, chúng tôi thoát với trạng thái thoát khác không, trong kịch bản shell có nghĩa là "chấm dứt lệnh không thành công."
Do đó , cách duy nhất lệnh Awk này sẽ thoát thành công là nếu kết thúc tập tin trước khi đạt đến dòng thứ 10.
Vì vậy, nếu tập lệnh Awk thoát thành công, điều đó có nghĩa là bạn có một tệp có ít hơn mười dòng.
Cuộc -exec
gọi tiếp theo (nếu bạn loại bỏ echo
) sẽ xóa từng tệp (sẽ tiến xa đến mức đánh giá các nguyên tắc find
) bằng cách chạy:
rm -f ./somefilename
Giả sử find
việc triển khai hỗ trợ biến -readable
vị ngữ (nếu bạn find
không hỗ trợ nó, chỉ cần xóa nó, bạn sẽ chỉ nhận được thông báo lỗi cho các tệp không thể đọc hoặc thay thế bằng -exec test -r {} \;
):
x=10 find . -type f -readable -exec sh -c '
for file do
lines=$(wc -l < "$file") && [ "$((lines))" -lt "$x" ] && echo rm -f "$file"
done' sh {} +
Gỡ bỏ echo
nếu hạnh phúc.
Điều đó không đặc biệt hiệu quả ở chỗ nó đếm tất cả các dòng trong mỗi tệp trong khi nó chỉ cần dừng lại ở dòng x
thứ nhất và nó chạy một wc
(và có khả năng là mộtrm
) cho mỗi tệp.
Với GNU awk
, bạn có thể làm cho nó hiệu quả hơn rất nhiều với:
x=10
find . -type f -readable -exec awk -v x="$x" -v ORS='\0' '
FNR == x {nextfile}
ENDFILE {if (FNR < x) print FILENAME}' {} +|
xargs -r0 echo rm -f
(một lần nữa, loại bỏ echo
khi hạnh phúc).
Tương tự với perl
:
x=10 find . -type f -readable -exec perl -Tlne '
if ($. == $ENV{x}) {close ARGV}
elsif (eof) {print $ARGV; close ARGV}' {} +
Thay thế print
bằng unlink
nếu hạnh phúc.
sh
là những gì diễn ra trong tập lệnh nội tuyến đó $0
, được sử dụng cho các thông báo lỗi chẳng hạn. wc -l "$file"
sẽ in tên tệp mà chúng tôi không muốn ở đây và sẽ chạy wc
ngay cả khi tệp không thể được mở. $x
được xuất sang find
( x=10 find...
) mà chính nó chuyển qua nó sh
.
find: -readable: unknown primary or operator
.
bash
. bash
chỉ là một trình thông dịch dòng lệnh, nhưng của việc find
thực hiện. -readable
là một phần mở rộng GNU, không có sẵn trong OS / X find
. Nó chỉ được sử dụng để giới hạn các tệp có thể đọc được (bạn sẽ không thể lấy số lượng dòng cho các tệp không thể đọc được). Bạn có thể bỏ qua nó cho lần đầu tiên, sau đó bạn sẽ nhận được thông báo lỗi khi mở các tệp wc
cho các tệp không thể đọc được.
Để hoàn thiện, bỏ qua AWK, bạn cũng có thể sử dụng GNU sed để đạt được kết quả tương tự:
find . -type f -exec sed 11q1 '{}' ';' -exec echo rm -f '{}' ';'
Mà kết quả trong một dòng lệnh ngắn gọn hơn một chút.
Giải trình
11 - is the address, i.e. "the eleventh line"
q - is for _q_uit (abort the execution)
1 - is the exit code parameter for q (GNU sed extension)
sh
để làm gì? 2. Cówc -l < "$file"
nhanh hơnwc -l "$file"
không? 3. Làm thế nào để sh biết giá trị của$x
, được định nghĩa trong shell Bash gọi?