Giả sử bạn có tệp txt, lệnh nào để xem đồng thời 10 dòng trên cùng và 10 dòng dưới cùng của tệp?
tức là nếu tệp dài 200 dòng, thì xem các dòng 1-10 và 190-200 trong một lần.
Giả sử bạn có tệp txt, lệnh nào để xem đồng thời 10 dòng trên cùng và 10 dòng dưới cùng của tệp?
tức là nếu tệp dài 200 dòng, thì xem các dòng 1-10 và 190-200 trong một lần.
Câu trả lời:
Bạn có thể chỉ cần:
(head; tail) < file.txt
Và nếu bạn cần sử dụng đường ống vì một số lý do thì như thế này:
cat file.txt | (head; tail)
Lưu ý: sẽ in các dòng trùng lặp nếu số dòng trong file.txt nhỏ hơn các dòng đầu mặc định + các dòng đuôi mặc định.
head
đã tiêu thụ 10 dòng đầu tiên của tệp. (So sánh điều này với head < file.txt; tail < file.txt
trên một tệp có ít hơn 20 dòng). Chỉ là một điểm rất nhỏ để ghi nhớ. (Nhưng vẫn là +1.)
head
chỉ hiển thị 10 dòng đầu tiên của đầu vào, nhưng không có gì đảm bảo rằng nó không tiêu thụ nhiều hơn để tìm dòng thứ 10 kết thúc, để lại ít đầu vào less
để hiển thị.
seq 100 | (head; tail)
chỉ cho tôi 10 số đầu tiên. Chỉ trên kích thước đầu vào lớn hơn nhiều (như seq 2000
), đuôi mới có được một số đầu vào.
Đối với một luồng thuần (ví dụ: đầu ra từ một lệnh), bạn có thể sử dụng 'tee' để rẽ nhánh luồng và gửi một luồng đến đầu và một luồng tới đuôi. Điều này yêu cầu sử dụng tính năng '> (danh sách)' của bash (+ / dev / fd / N):
( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
hoặc sử dụng / dev / fd / N (hoặc / dev / stderr) cộng với các chuỗi con với chuyển hướng phức tạp:
( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1
(Cả hai thứ này sẽ không hoạt động trong csh hoặc tcsh.)
Đối với một cái gì đó có kiểm soát tốt hơn một chút, bạn có thể sử dụng lệnh perl này:
COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
COMMAND | { tee >(head >&2) | tail; } |& other_commands
cat >/dev/null
sửa nó:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
head
và tail
lệnh: \ ...
head -10 file.txt; tail -10 file.txt
Ngoài ra, bạn sẽ cần phải viết chương trình / kịch bản của riêng bạn.
cat
và head
hoặc tail
đường ống, thật tốt khi biết rằng tôi có thể sử dụng chúng riêng lẻ!
{ head file; tail file; } | prog
(khoảng cách bên trong dấu ngoặc nhọn và dấu chấm phẩy được yêu cầu)
Dựa trên nhận xét của JF Sebastian :
cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1
Bằng cách này, bạn có thể xử lý dòng đầu tiên và phần còn lại khác nhau trong một ống, rất hữu ích khi làm việc với dữ liệu CSV:
{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
N * 2 2 4 6
vấn đề ở đây là các chương trình hướng luồng không biết trước độ dài của tệp (vì có thể không có tệp nào, nếu đó là luồng thực).
các công cụ như tail
đệm n dòng cuối cùng nhìn thấy và đợi đến cuối luồng, sau đó in.
nếu bạn muốn thực hiện điều này trong một lệnh duy nhất (và để nó hoạt động với bất kỳ phần bù nào và không lặp lại các dòng nếu chúng trùng nhau), bạn sẽ phải mô phỏng hành vi này mà tôi đã đề cập.
thử cái này đi
awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile
a.out | awk -v ...
Phải mất rất nhiều thời gian để kết thúc với giải pháp này, dường như là giải pháp duy nhất bao gồm tất cả các trường hợp sử dụng (cho đến nay):
command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
'{
if (NR <= offset) print;
else {
a[NR] = $0;
delete a[NR-offset];
printf "." > "/dev/stderr"
}
}
END {
print "" > "/dev/stderr";
for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
{ print a[i]}
}'
Danh sách tính năng:
Tôi đã tìm kiếm giải pháp này trong một thời gian. Đã thử nó với sed, nhưng vấn đề không biết chiều dài của tập tin / luồng trước đó là không thể vượt qua. Trong tất cả các tùy chọn có sẵn ở trên, tôi thích giải pháp awk của Camille Goudeseune. Anh ta đã lưu ý rằng giải pháp của anh ta để lại các dòng trống thừa ở đầu ra với một bộ dữ liệu đủ nhỏ. Ở đây tôi cung cấp một sửa đổi của giải pháp của mình mà loại bỏ các dòng thêm.
headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }
Chà, bạn luôn có thể xâu chuỗi chúng lại với nhau. Giống như vậy ,
head fiename_foo && tail filename_foo
. Nếu điều đó là không đủ, bạn có thể tự viết cho mình một hàm bash trong tệp .profile hoặc bất kỳ tệp đăng nhập nào bạn sử dụng:
head_and_tail() {
head $1 && tail $1
}
Và, sau đó gọi nó từ dấu nhắc shell của bạn : head_and_tail filename_foo
.
10 dòng đầu tiên của file.ext, sau đó là 10 dòng cuối cùng của nó:
cat file.ext | head -10 && cat file.ext | tail -10
10 dòng cuối cùng của tệp, sau đó là 10 dòng đầu tiên:
cat file.ext | tail -10 && cat file.ext | head -10
Sau đó, bạn cũng có thể dẫn đầu ra ở nơi khác:
(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program
tail
và head
hoặc một hàm bằng cách đặt bí danh cho nó.
Tôi đã viết một ứng dụng python đơn giản để làm điều này: https://gist.github.com/ÿvdm/9970522
Nó xử lý các đường ống (luồng) cũng như các tập tin.
Để xử lý các đường ống (luồng) cũng như các tệp, hãy thêm tệp này vào tệp .bashrc hoặc .profile của bạn:
headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; }
Sau đó, bạn không thể chỉ
headtail 10 < file.txt
nhưng cũng
a.out | headtail 10
(Điều này vẫn nối các dòng trống giả khi 10 vượt quá độ dài của đầu vào, không giống như cũ a.out | (head; tail)
. Cảm ơn bạn, những người trả lời trước.)
Lưu ý : headtail 10
, không headtail -10
.
Dựa trên những gì @Samus_ đã giải thích ở đây về cách hoạt động của lệnh @Aleksandra Zalcman, biến thể này rất hữu ích khi bạn không thể nhanh chóng phát hiện ra nơi đuôi bắt đầu mà không cần đếm dòng.
{ head; echo "####################\n...\n####################"; tail; } < file.txt
Hoặc nếu bạn bắt đầu làm việc với thứ gì đó ngoài 20 dòng, số lượng dòng thậm chí có thể giúp ích.
{ head -n 18; tail -n 14; } < file.txt | cat -n
Để in 10 dòng đầu tiên và 10 dòng cuối cùng của tệp, bạn có thể thử điều này:
cat <(head -n10 file.txt) <(tail -n10 file.txt) | less
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"
LƯU Ý : Biến aFile chứa đường dẫn đầy đủ của tệp .
Tôi sẽ nói rằng tùy thuộc vào kích thước của tập tin, việc chủ động đọc nội dung của nó có thể không được mong muốn. Trong hoàn cảnh đó, tôi nghĩ rằng một số kịch bản shell đơn giản nên đủ.
Đây là cách gần đây tôi đã xử lý việc này cho một số tệp CSV rất lớn mà tôi đang phân tích:
$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
Điều này in ra 10 dòng đầu tiên và 10 dòng cuối cùng của mỗi tệp, đồng thời in ra tên tệp và một số dấu chấm lửng trước và sau.
Đối với một tệp lớn, bạn có thể chỉ cần chạy như sau để có cùng hiệu quả:
$ head somefile.csv && echo ... && tail somefile.csv
Tiêu thụ stdin, nhưng đơn giản và hoạt động cho 99% trường hợp sử dụng
#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT
$ seq 100 | head_and_tail 4
1
2
3
4
...
97
98
99
100