Katakanlah Anda memiliki file txt, apa perintah untuk melihat 10 baris teratas dan 10 baris teratas file secara bersamaan?
yaitu jika file tersebut panjangnya 200 baris, maka lihat baris 1-10 dan 190-200 dalam sekali jalan.
Katakanlah Anda memiliki file txt, apa perintah untuk melihat 10 baris teratas dan 10 baris teratas file secara bersamaan?
yaitu jika file tersebut panjangnya 200 baris, maka lihat baris 1-10 dan 190-200 dalam sekali jalan.
Jawaban:
Anda cukup:
(head; tail) < file.txt
Dan jika Anda perlu menggunakan pipa untuk beberapa alasan maka seperti ini:
cat file.txt | (head; tail)
Catatan: akan mencetak baris duplikat jika jumlah baris dalam file.txt lebih kecil dari garis kepala standar + garis ekor standar.
head
mengkonsumsi 10 baris pertama file. (Bandingkan ini dengan head < file.txt; tail < file.txt
pada file dengan kurang dari 20 baris). Hanya poin yang sangat kecil untuk diingat. (Tapi tetap +1.)
head
hanya menampilkan 10 baris pertama dari inputnya, tidak ada jaminan bahwa itu tidak mengkonsumsi lebih banyak untuk menemukan baris ke-10 berakhir, menyisakan lebih sedikit input untuk less
ditampilkan.
seq 100 | (head; tail)
memberi saya hanya 10 nomor pertama. Hanya pada ukuran input yang jauh lebih besar (seperti seq 2000
) ekornya mendapat beberapa input.
Untuk stream murni (misalnya output dari perintah), Anda dapat menggunakan 'tee' untuk memotong stream dan mengirim satu stream ke head dan satu ke tail. Ini memerlukan penggunaan fitur '> (daftar)' dari bash (+ / dev / fd / N):
( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
atau menggunakan / dev / fd / N (atau / dev / stderr) ditambah subkulit dengan pengalihan rumit:
( ( 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
(Tidak satu pun dari ini akan bekerja dalam csh atau tcsh.)
Untuk sesuatu dengan kontrol yang sedikit lebih baik, Anda dapat menggunakan perintah perl ini:
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
memperbaikinya:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
head
dan tail
perintah: \ ...
head -10 file.txt; tail -10 file.txt
Selain itu, Anda harus menulis program / skrip Anda sendiri.
cat
dan head
atau tail
disalurkan, senang mengetahui bahwa saya dapat menggunakannya secara individual!
{ head file; tail file; } | prog
(spasi di dalam kurung, dan tanda titik koma diperlukan)
Berdasarkan komentar JF Sebastian :
cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1
Dengan cara ini Anda dapat memproses baris pertama dan lainnya secara berbeda dalam satu pipa, yang berguna untuk bekerja dengan data 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
masalahnya di sini adalah bahwa program yang berorientasi pada aliran tidak tahu panjang file di muka (karena mungkin tidak ada, jika itu adalah aliran nyata).
alat-alat seperti tail
buffer n baris terakhir terlihat dan menunggu akhir aliran, lalu cetak.
jika Anda ingin melakukan ini dalam satu perintah (dan membuatnya bekerja dengan offset apa pun, dan jangan ulangi baris jika tumpang tindih) Anda harus meniru perilaku yang saya sebutkan ini.
coba awk ini:
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 ...
Butuh banyak waktu untuk menyelesaikan dengan solusi ini yang, tampaknya menjadi satu-satunya yang mencakup semua kasus penggunaan (sejauh ini):
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]}
}'
Daftar fitur:
Saya telah mencari solusi ini untuk sementara waktu. Mencoba sendiri dengan sed, tetapi masalah dengan tidak mengetahui panjang file / stream sebelumnya tidak dapat diatasi. Dari semua opsi yang tersedia di atas, saya suka solusi awk Camille Goudeseune. Dia memang membuat catatan bahwa solusinya meninggalkan garis kosong tambahan dalam output dengan set data yang cukup kecil. Di sini saya memberikan modifikasi dari solusinya yang menghilangkan garis ekstra.
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] }' ; }
Nah, Anda selalu bisa rantai mereka bersama. Seperti itu
head fiename_foo && tail filename_foo
,. Jika itu tidak cukup, Anda bisa menulis sendiri fungsi bash di file .profile Anda atau file login apa pun yang Anda gunakan:
head_and_tail() {
head $1 && tail $1
}
Dan, kemudian memanggil dari shell Anda cepat: head_and_tail filename_foo
.
10 baris file.ext pertama, lalu 10 baris terakhir:
cat file.ext | head -10 && cat file.ext | tail -10
10 baris terakhir file, lalu 10 baris pertama:
cat file.ext | tail -10 && cat file.ext | head -10
Anda kemudian dapat mengirimkan output ke tempat lain juga:
(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program
tail
dan head
atau fungsi dengan alias-ing.
Saya menulis aplikasi python sederhana untuk melakukan ini: https://gist.github.com/garyvdm/9970522
Ini menangani pipa (stream) serta file.
Untuk menangani pipa (stream) dan juga file, tambahkan ini ke file .bashrc atau .profile Anda:
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] }' ; }
Maka Anda tidak bisa hanya
headtail 10 < file.txt
tetapi juga
a.out | headtail 10
(Ini masih menambahkan baris kosong palsu ketika 10 melebihi panjang input, tidak seperti biasa a.out | (head; tail)
. Terima kasih, penjawab sebelumnya.)
Catatan:, headtail 10
tidak headtail -10
.
Membangun apa yang dijelaskan oleh @Samus_ di sini tentang cara kerja perintah @Alexandra Zalcman, variasi ini berguna ketika Anda tidak dapat dengan cepat melihat di mana ekor dimulai tanpa menghitung garis.
{ head; echo "####################\n...\n####################"; tail; } < file.txt
Atau jika Anda mulai bekerja dengan sesuatu selain 20 baris, jumlah baris bahkan mungkin membantu.
{ head -n 18; tail -n 14; } < file.txt | cat -n
Untuk mencetak 10 baris pertama dan 10 baris terakhir dari sebuah file, Anda dapat mencoba ini:
cat <(head -n10 file.txt) <(tail -n10 file.txt) | less
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"
CATATAN : Variabel aFile berisi path lengkap file .
Saya akan mengatakan bahwa tergantung pada ukuran file, membaca isinya secara aktif mungkin tidak diinginkan. Dalam keadaan itu, saya pikir beberapa skrip shell sederhana sudah cukup.
Inilah cara saya baru-baru ini menangani ini untuk sejumlah file CSV yang sangat besar yang saya analisis:
$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
Ini mencetak 10 baris pertama dan 10 baris terakhir dari setiap file, sementara juga mencetak nama file dan beberapa elipsis sebelum dan sesudah.
Untuk satu file besar, Anda bisa menjalankan yang berikut untuk efek yang sama:
$ head somefile.csv && echo ... && tail somefile.csv
Mengkonsumsi stdin, tetapi sederhana dan berfungsi untuk 99% kasus penggunaan
#!/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