Jadi ini untuk pekerjaan rumah, tapi saya tidak akan menanyakan pertanyaan pekerjaan rumah tertentu.
Saya perlu menggunakan kepala dan ekor untuk mengambil set garis yang berbeda dari satu file. Jadi seperti baris 6-11 dan baris 19-24 dan simpan keduanya ke file lain. Saya tahu saya bisa melakukan ini menggunakan append seperti
head -11 file|tail -6 > file1; head -24 file| tail -6 >> file1.
Tapi saya pikir kita tidak seharusnya begitu.
Apakah ada cara khusus saya bisa menggabungkan perintah kepala dan ekor dan kemudian menyimpan ke file?
head
dantail
? Jika demikian, solusi Anda adalah yang terbaik yang dapat Anda lakukan. Jika Anda diizinkan menggunakan program lain,sed
atauawk
mungkin mengizinkan solusi yang lebih bagus (mis. Dengan lebih sedikit pemanggilan proses).>>
) dengan melampirkan dua perintah dalam kurung untuk mengarahkan output bersambung mereka:(head -11 file | tail -6; head -24 file | tail -6) > file1
. Itu benar-benar turun ke preferensi pribadi yang lebih baik.Jawaban:
Anda dapat melakukannya dengan
head
aritmatika sendiri dan dasar, jika Anda mengelompokkan perintah dengan{ ... ; }
menggunakan konstruk likedi mana semua perintah berbagi input yang sama (terima kasih @mikeserv ).
Mendapatkan garis 6-11 dan garis 19-24 setara dengan:
Jadi, pada dasarnya, Anda akan menjalankan:
sumber
Anda bisa menggunakan
{ … }
konstruk pengelompokan untuk menerapkan operator pengalihan ke perintah gabungan.Alih-alih menduplikasi baris M + N pertama dan hanya mempertahankan N terakhir, Anda dapat melewati baris M pertama dan menduplikasi N. berikutnya. Ini lebih cepat terukur pada file besar . Berhati-hatilah bahwa
+N
argumen daritail
bukan jumlah baris untuk dilewati, tetapi satu ditambah itu - itu adalah jumlah baris pertama yang akan dicetak dengan garis bernomor mulai dari 1.Either way, file output hanya dibuka sekali, tetapi file input dilewati sekali untuk setiap potongan untuk diekstraksi. Bagaimana dengan pengelompokan input?
Secara umum, ini tidak berhasil. (Mungkin bekerja pada beberapa sistem, setidaknya ketika inputnya adalah file biasa.) Mengapa? Karena input buffering . Sebagian besar program, termasuk
tail
, tidak membaca input byte demi byte, tetapi beberapa kilobyte pada satu waktu, karena lebih cepat. Jaditail
membaca beberapa kilobyte, melompati sedikit di awal, melewati sedikit lebih kehead
, dan berhenti - tetapi apa yang dibaca dibaca, dan tidak tersedia untuk perintah berikutnya.Pendekatan lain adalah menggunakan
head
piped/dev/null
untuk melewati garis.Sekali lagi, ini tidak dijamin berfungsi, karena buffering. Itu terjadi untuk bekerja dengan
head
perintah dari GNU coreutils (yang ditemukan pada sistem Linux yang tidak tertanam), ketika input dari file biasa. Itu karena setelah implementasi inihead
telah membaca apa yang diinginkannya, ia menetapkan posisi file ke byte pertama yang tidak di-output. Ini tidak berfungsi jika inputnya adalah pipa.Cara yang lebih sederhana untuk mencetak beberapa urutan garis dari suatu file adalah dengan memanggil alat yang lebih umum seperti sed atau awk . (Ini bisa lebih lambat, tetapi hanya penting untuk file yang sangat besar.)
sumber
Saya tahu Anda mengatakan bahwa Anda perlu menggunakan kepala dan ekor, tetapi sed jelas merupakan alat yang lebih sederhana untuk pekerjaan di sini.
Anda bahkan dapat membangun blok dalam string dengan beberapa proses lain dan menjalankannya melalui sed.
-n meniadakan output, maka Anda menentukan rentang untuk dicetak dengan p, dengan nomor pertama dan terakhir dari rentang dipisahkan oleh koma.
Yang sedang berkata, Anda bisa melakukan pengelompokan perintah yang disarankan @don_crissti, atau loop melalui file beberapa kali dengan kepala / ekor meraih sepotong garis setiap kali Anda melewati.
Semakin banyak baris dalam file dan semakin banyak blok yang Anda miliki, semakin efisien pula caranya.
sumber
Dengan
sed
Anda mungkin melakukannya:... Mungkin solusi yang lebih efisien dapat diperoleh
head
. Don sudah mendemonstrasikan bagaimana itu bisa bekerja dengan sangat baik, tetapi saya juga bermain-main dengannya. Sesuatu yang mungkin Anda lakukan untuk menangani kasus khusus ini:... yang akan memanggil
head
4 kali penulisan untukoutfile
atau/dev/null
tergantung pada apakah nilai iterasi untuk$n
angka genap atau ganjil.Untuk kasus-kasus yang lebih umum, saya menggabungkan ini dari beberapa hal lain yang sudah saya miliki:
Ini dapat melakukan hal Anda seperti:
... yang mencetak ...
Ia mengharapkan arg pertama menjadi hitungan berulang yang diawali dengan
-
, atau, gagal itu, hanya a-
. Jika hitungan diberikan, ia akan mengulangi pola garis yang diberikan dalam argumen berikut sebanyak yang ditentukan dan berhenti segera setelah itu dilakukan.Untuk setiap argumen yang mengikutinya akan menafsirkan bilangan bulat negatif untuk menunjukkan jumlah baris yang harus ditulis
/dev/null
dan bilangan bulat positif untuk menunjukkan jumlah baris yang harus ditulisstdout
.Jadi pada contoh di atas ia mencetak 5 baris pertama
/dev/null
, 6 berikutnyastdout
, 7 berikutnya/dev/null
lagi dan 6 berikutnya sekali lagistdout
. Setelah mencapai argumen terakhir dan sepenuhnya berputar melalui-1
hitungan ulang, ia kemudian berhenti. Jika arg pertama adalah-2
itu akan mengulangi proses sekali lagi, atau jika-
selama itu bisa.Untuk setiap siklus arg,
while
loop diproses sekali melalui. Di bagian atas setiap loop, baris pertama daristdin
dibaca ke variabel shell$l
. Hal ini diperlukan karenawhile head </dev/null; do :; done
akan mengulangi tanpa batas -head
tidak menunjukkan pengembalian ketika telah mencapai akhir file. Jadi pemeriksaan terhadap EOF didedikasikan untukread
danprintf
akan menulis$l
plus baris barustdout
hanya jika argumen kedua adalah bilangan bulat positif.The
read
cek mempersulit loop kecil karena segera setelah loop lain disebut - sebuahfor
lingkaran yang iterates atas args2-$#
yang diwakili di$n
setiap iterasi dari induknyawhile
lingkaran. Ini berarti bahwa untuk setiap iterasi, arg pertama harus dikurangi dengan satu dari nilai yang ditentukan pada baris perintah, tetapi semua yang lain harus mempertahankan nilai aslinya, sehingga nilai$_n
marker var dikurangkan dari masing-masing, tetapi hanya pernah memegang nilai lebih besar dari 0 untuk arg pertama.Itu merupakan loop utama dari fungsi, tetapi sebagian besar kode berada di bagian atas dan dimaksudkan untuk memungkinkan fungsi untuk buffer bahkan pipa sebagai input. Ini bekerja dengan terlebih dahulu memanggil latar belakang
dd
untuk menyalinnya ke tmpfile pada output di bloksi 4k sepotong. Fungsi ini kemudian mengatur loop terus - yang seharusnya hampir tidak pernah menyelesaikan bahkan satu siklus penuh - hanya untuk memastikan bahwadd
telah membuat setidaknya satu tulis ke file sebelum fungsi kemudian mengganti stdin dengan deskriptor file yang terhubung ke tmpfile dan setelah itu segera putuskan tautan file denganrm
. Hal ini memungkinkan fungsi untuk memproses aliran secara andal tanpa memerlukan jebakan atau sebaliknya untuk pembersihan - segera setelah fungsi melepaskannya mengklaim pada fd tmpfile akan tidak ada lagi karena satu-satunya tautan filesystem yang dinamai telah dihapus.sumber
Gunakan fungsi bash seperti ini:
Ini sedikit berlebihan dalam hal ini, tetapi jika filter Anda tumbuh lebih besar itu bisa menjadi anugerah.
sumber