Có lẽ cách tốt nhất để làm điều này là với chuyển hướng vỏ, như những người khác đã đề cập. sed
mặc dù, trong khi yêu thích cá nhân, có lẽ sẽ không làm điều này hiệu quả hơn ý muốn head
- được thiết kế để chỉ lấy quá nhiều dòng từ một tệp.
Có những câu trả lời khác trên trang web này cho thấy rõ ràng rằng đối với các tệp lớn head -n[num] | tail -n[num]
sẽ vượt trội hơn sed
mọi lúc, nhưng có lẽ còn nhanh hơn thế nữa là tránh hoàn toàn đường ống.
Tôi đã tạo một tệp như:
echo | dd cbs=5000000 conv=block | tr \ \\n >/tmp/5mil_lines
Và tôi đã chạy nó qua:
{ head -n "$((ignore=2762817))" >&2
head -n "$((2853648-ignore))"
} </tmp/5mil_lines 2>/dev/null |
sed -n '1p;$p'
Tôi chỉ sử dụng sed
tất cả ở đó để chỉ lấy dòng đầu tiên và cuối cùng để hiển thị cho bạn ...
2762818
2853648
Điều này hoạt động bởi vì khi bạn nhóm các lệnh với { ... ; }
và chuyển hướng đầu vào cho nhóm giống như ... ; } <input
tất cả chúng sẽ chia sẻ cùng một đầu vào. Hầu hết các lệnh sẽ làm cạn kiệt toàn bộ infile trong khi đọc nó, vì vậy trong một { cmd1 ; cmd2; } <infile
trường hợp thường cmd1
đọc từ đầu của infile đến đuôi của nó và cmd2
không có gì cả.
head
, tuy nhiên, sẽ luôn luôn chỉ tìm kiếm cho đến nay thông qua sự vô dụng của nó như được hướng dẫn để làm, và vì vậy trong một ...
{ head -n [num] >/dev/null
head -n [num]
} <infile
... trong trường hợp người đầu tiên tìm kiếm [num]
và bỏ kết quả đầu ra của nó /dev/null
và lần thứ hai còn lại để bắt đầu đọc nơi đầu tiên rời khỏi nó.
Bạn có thể làm...
{ head -n "$((ignore=2762817))" >/dev/null
head -n "$((2853648-ignore))" >/path/to/outfile
} <infile
Cấu trúc này cũng hoạt động với các loại lệnh ghép khác. Ví dụ:
set "$((n=2762817))" "$((2853648-n))"
for n do head "-n$n" >&"$#"; shift
done <5mil_lines 2>/dev/null |
sed -n '1p;$p'
... mà in ...
2762818
2853648
Nhưng nó cũng có thể hoạt động như sau:
d=$((( n=$(wc -l </tmp/5mil_lines))/43 )) &&
until [ "$(((n-=d)>=(!(s=143-n/d))))" -eq 0 ] &&
head "-n$d" >>"/tmp/${s#1}.split"
do head "-n$d" > "/tmp/${s#1}.split" || ! break
done </tmp/5mil_lines
Trên vỏ ban đầu đặt $n
và $d
các biến thành ...
$n
- Số dòng được báo cáo bởi
wc
tệp thử nghiệm của tôi/tmp/5mil_lines
$d
- Thương số của
$n/43
43 chỉ là một số chia được chọn tùy ý.
Sau đó nó vòng until
nó đã giảm đi $n
bởi $d
một giá trị ít $d
. Trong khi làm như vậy, nó lưu số đếm tách của nó $s
và sử dụng giá trị đó trong vòng lặp để tăng >
tệp đầu ra được đặt tên được gọi /tmp/[num].split
. Kết quả là nó đọc ra một số lượng tương đương các \n
trường được phân tách bằng ewline trong phần lưu trữ của nó thành một tệp dữ liệu mới cho mỗi lần lặp - chia nó ra bằng 43 lần trong suốt vòng lặp. Nó quản lý nó mà không cần phải đọc dữ liệu của nó quá 2 lần - lần đầu tiên là khi wc
nó đếm các dòng của nó và trong phần còn lại của hoạt động, nó chỉ đọc nhiều dòng như nó ghi vào outfile mỗi lần.
Sau khi chạy nó, tôi đã kiểm tra kết quả của mình như ...
tail -n1 /tmp/*split | grep .
ĐẦU RA:
==> /tmp/01.split <==
116279
==> /tmp/02.split <==
232558
==> /tmp/03.split <==
348837
==> /tmp/04.split <==
465116
==> /tmp/05.split <==
581395
==> /tmp/06.split <==
697674
==> /tmp/07.split <==
813953
==> /tmp/08.split <==
930232
==> /tmp/09.split <==
1046511
==> /tmp/10.split <==
1162790
==> /tmp/11.split <==
1279069
==> /tmp/12.split <==
1395348
==> /tmp/13.split <==
1511627
==> /tmp/14.split <==
1627906
==> /tmp/15.split <==
1744185
==> /tmp/16.split <==
1860464
==> /tmp/17.split <==
1976743
==> /tmp/18.split <==
2093022
==> /tmp/19.split <==
2209301
==> /tmp/20.split <==
2325580
==> /tmp/21.split <==
2441859
==> /tmp/22.split <==
2558138
==> /tmp/23.split <==
2674417
==> /tmp/24.split <==
2790696
==> /tmp/25.split <==
2906975
==> /tmp/26.split <==
3023254
==> /tmp/27.split <==
3139533
==> /tmp/28.split <==
3255812
==> /tmp/29.split <==
3372091
==> /tmp/30.split <==
3488370
==> /tmp/31.split <==
3604649
==> /tmp/32.split <==
3720928
==> /tmp/33.split <==
3837207
==> /tmp/34.split <==
3953486
==> /tmp/35.split <==
4069765
==> /tmp/36.split <==
4186044
==> /tmp/37.split <==
4302323
==> /tmp/38.split <==
4418602
==> /tmp/39.split <==
4534881
==> /tmp/40.split <==
4651160
==> /tmp/41.split <==
4767439
==> /tmp/42.split <==
4883718
==> /tmp/43.split <==
5000000
sed
để tạo một tệp mới nếu không tồn tại? Ngay bây giờ tôi đang nhận đượcsed: can't read /var/log/output.txt: No such file or directory
. Tất nhiên tôi chỉ có thể tạo một tập tin, nhưng để học hỏi, tôi muốn biết làm thế nào để tự động làm nó.