Bagaimana cara menghapus n baris pertama dan baris terakhir file menggunakan perintah shell?


31

Saya memiliki file bernama yang Element_queryberisi hasil dari permintaan:

SQL> select count (*) from element;

[Output of the query which I want to keep in my file]

SQL> spool off;

Saya ingin menghapus baris 1 dan baris terakhir menggunakan perintah shell.


2
Anda mungkin sebaiknya memperbaiki ini di dalam SQL * Plus; Daripada menghasilkan file dan kemudian mencoba untuk memangkas hal-hal yang tidak Anda inginkan, Anda bisa saja mengatakan SQL * Plus untuk tidak menghasilkan hal-hal itu untuk memulai. Satu pendekatan dijelaskan di bagian "Membuat File Rata" di docs.oracle.com/cd/A84870_01/doc/sqlplus.816/a75664/ch44.htm ; pendekatan lain dijelaskan di stackoverflow.com/q/2299375/978917 .
ruakh

Jawaban:


48

Menggunakan GNU sed:

sed -i '1d;$d' Element_query

Bagaimana itu bekerja :

  • -iopsi edit file itu sendiri. Anda juga bisa menghapus opsi itu dan mengarahkan output ke file baru atau perintah lain jika Anda mau.
  • 1dmenghapus baris pertama ( 1hanya untuk bertindak pada baris pertama,d untuk menghapusnya)
  • $dmenghapus baris terakhir ( $hanya untuk bertindak pada baris terakhir, duntuk menghapusnya)

Lebih jauh:

  • Anda juga dapat menghapus rentang. Sebagai contoh,1,5d akan menghapus 5 baris pertama.
  • Anda juga dapat menghapus setiap baris yang dimulai dengan SQL> menggunakan pernyataan/^SQL> /d
  • Anda dapat menghapus setiap baris kosong dengan /^$/d
  • Akhirnya, Anda dapat menggabungkan pernyataan dengan memisahkannya dengan tanda titik koma ( statement1;statement2;satement3;...) atau dengan menentukannya secara terpisah pada baris perintah ( -e 'statement1' -e 'statement 2' ...)

Jika baris ke-3 untuk dihapus ... maka saya harus menggunakan 3d di tempat 1d? jika baris ke-3 dari yang terakhir dihapus ... lalu apa yang akan menjadi perintah?
pmaipmui

Bagaimana cara menghapus baris ke-3 dari perintah shell menggunakan terakhir?
pmaipmui

@Nainita Anda dapat menentukan rentang ( 1,3dakan menghapus tiga baris pertama) tetapi sedikit lebih sulit untuk akhirnya. Tergantung pada apa yang Anda inginkan, Anda bisa lebih baik menggunakan ini: sed -i '/^SQL> /d' Element_queryuntuk menghapus baris yang dimulai SQL> tanpa peduli di mana file itu berada.
user43791

@Nainita - lihat jawaban saya di sini untuk jumlah ekor yang sewenang-wenang - ini menawarkan dua solusi untuk menghapus garis jumlah relatif terhadap akhir file. Satu adalah sedsatu-liner - yang akan bekerja untuk menghilangkan jumlah baris sewenang-wenang dari kepala dan ekor file, Lebih baik, selama input adalah file biasa, hanya untuk mengelompokkan satu input tunggal di dua headproses - itu adalah Cara tercepat untuk melakukan ini biasanya.
mikeserv

Saya dulu sed -i '1d' table-backup.sqlmenghapus baris pertama file teks sql
David Thomas

8

kepala; kepala

{   head -n[num] >/dev/null
    head -n[num]
}  <infile >outfile

Dengan di atas, Anda dapat menentukan jumlah baris pertama yang akan dilepas dari kepala keluaran dengan headperintah pertama , dan jumlah baris yang akan ditulis outfiledengan yang kedua. Biasanya juga akan melakukan ini lebih cepat daripada sed- terutama ketika input besar - meskipun membutuhkan dua doa. Mana sedpasti harus lebih disukai meskipun, adalah dalam hal <infileini tidak biasa, lseekable berkas - karena ini biasanya akan tidak bekerja sebagaimana dimaksud dalam kasus itu, namun seddapat menangani semua modifikasi output dalam proses tunggal, scripted.

Dengan GNU headAnda bisa menggunakan -formulir negatif untuk [num]di perintah kedua juga. Dalam hal ini perintah berikut akan menghapus baris pertama dan terakhir dari input:

{   head -n1 >/dev/null
    head -n-1
}  <infile >outfile

ATAU dengan POSIX sed:

Katakan, misalnya, saya membaca input 20 baris dan saya ingin menghapus 3 dan 7 yang terakhir. Jika saya memutuskan untuk melakukannya dengan sed, saya akan melakukannya dengan buffer ekor. Pertama-tama saya akan menambahkan tiga dan tujuh untuk jumlah total strip dan kemudian melakukan:

seq 20 | sed -ne:n -e '3d;N;1,10bn' -eP\;D

Itu adalah contoh yang menghapus 3 baris pertama dan 7 baris terakhir dari input. Idenya adalah bahwa Anda dapat menyangga sebanyak mungkin garis yang ingin Anda lepas dari ujung input di ruang pola pada tumpukan tetapi hanya Pmemotong yang pertama untuk setiap baris yang ditarik.

  • Pada baris 1,10 sed Ptidak ada apapun karena untuk masing-masing input susun dalam ruang pola garis-demi-baris dalam bloop peternakan.
  • Pada baris ke-3 semua sedtumpukan ddihapus - dan sehingga 3 baris pertama dilepaskan dari output dalam satu gerakan.
  • Ketika sedmencapai $baris input terakhir dan mencoba menarik Next, hits EOF dan berhenti memproses seluruhnya. Tetapi pada saat itu, ruang pola mengandung semua garis 14,20- tidak ada yang belum Pdirusak, dan tidak pernah ada.
  • Pada setiap baris lainnya, sed Pjalankan hanya hingga baris pertama yang terjadi \ndi ruang pola, dan Dhapus yang sama sebelum memulai siklus baru dengan apa yang tersisa - atau 6 baris input berikutnya. Baris ke-7 ditambahkan lagi ke stack dengan Nperintah ext dalam siklus baru.

Jadi, dari seqoutput (yaitu 20 baris bernomor berurutan) , sedhanya mencetak:

4
5
6
7
8
9
10
11
12
13

Ini menjadi bermasalah ketika jumlah garis yang ingin Anda lepas dari buntut input besar - karena sedkinerja berbanding lurus dengan ukuran ruang pola. Namun, tetap saja, ini adalah solusi yang layak dalam banyak kasus - dan POSIX menentukan sedruang pola untuk menangani setidaknya 4kb sebelum penghancuran.


1
gnu tailjuga mendukung tail -n+<num>sintaks yang diperluas yang berarti "mulai dari baris <num>"
UloPe

4

Saya tidak akan menjawab cara menghapus sejumlah baris. Saya akan menyerang masalah dengan cara ini:

grep -v '#SQL>' Element_query >outfile

Alih-alih menghitung baris, ini menghilangkan perintah SQL dengan mengenali petunjuknya. Solusi ini kemudian dapat digeneralisasi untuk file output lain dari sesi SQL dengan lebih banyak perintah daripada hanya dua.


Saya suka itu. Saya tidak tahu banyak tentang SQL - tetapi apakah tidak ada kemungkinan prompt terjadi di kepala jalur outputnya?
mikeserv

4

edadalah 'editor teks standar' dan harus tersedia pada sistem yang tidak memiliki GNU sed. Ini awalnya dirancang sebagai editor teks, tetapi sangat cocok untuk skrip.

printf '%s\n' 1d '$d' w q | ed Element_query

1dmenghapus baris pertama file, $d(dikutip agar shell tidak menganggap itu variabel) menghapus baris terakhir, wmenulis file dan qberhenti ed. printfdi sini digunakan untuk memformat perintah untuk ed- masing-masing harus diikuti oleh baris baru; tentu saja ada cara lain untuk mencapai hal ini.


3

Ada beberapa cara untuk menghapus baris awal dan akhir dari file.

Anda dapat menggunakannya awkkarena menangani pencocokan pola dan penghitungan garis,

#you need to know length to skip last line, assume we have 100 lines
awk 'NR>1 && NR<100 {print $0};' < inputfile
#or
awk '/SQL/ {next}; {print $0;};' < inputfile |awk 'NR>1&& NR<10 {print $0};'

Anda dapat menggunakan grep -vuntuk mengecualikan garis yang tidak Anda inginkan berdasarkan pola, dan Anda dapat mencocokkan beberapa pola menggunakan -Eopsi,

grep -v -E "SQL>" < inputfile > outputfile

Anda dapat menggunakan headdan tailuntuk memangkas jumlah garis tertentu,

lines=$((`wc -l < inputfile`-2)) #how many lines in file, less 2
head -n-1 < inputfile | head -n$lines > outputfile
#or
tail -n+2 < inputfile | head -n$lines > outputfile

Anda dapat menggunakan vi/vim, dan menghapus baris pertama dan terakhir,

vi inputfile
:1
dd
:$
dd
:w! outputfile
:x

Anda bisa menggunakan skrip perl, lewati baris pertama, simpan setiap baris, cetak ketika Anda mendapatkan baris berikutnya,

#left as exercise for the reader :-)

1
Untuk si headAnda tidak benar-benar membutuhkan pipa, dan, sebenarnya lebih baik tidak menggunakannya sama sekali jika Anda bisa lolos begitu saja. Ketika Anda melakukannya head | head- sementara kedua proses dapat berjalan secara bersamaan, keduanya juga memproses hampir semua data yang sama secara berlebihan. Jika Anda melakukannya, { head >dump; head >save; } <inAnda hanya melompat dengan offset - yang pertama membaca 10 baris ke >dumpdan yang kedua membaca 10 baris berikutnya ke >save.
mikeserv

3

Anda akan jauh lebih baik dilayani dengan memotong perintah SQL. Anda dapat melakukan ini dengan dua cara:

  1. Jika Anda benar - benar yakin bahwa urutan " SQL>" tidak terjadi di tempat lain di output,

    grep -v -F 'SQL> ' < infile > outfile
  2. Jika Anda tidak yakin,

    grep -v '^SQL> .*;$' < infile > outfile

Versi kedua lebih lambat tetapi lebih akurat: ia akan mengabaikan baris yang diawali dengan "SQL>" dan berakhir dengan titik koma, yang sepertinya menggambarkan garis yang ingin Anda hapus.

Namun, akan lebih baik untuk tidak memasukkan output ekstra dalam file untuk memulai. Sebagian besar sistem SQL memiliki beberapa cara untuk melakukan itu. Saya tidak terlalu fasih dengan Oracle, tapi mungkin jawaban ini mungkin bisa membantu.


3

Anda dapat memilih garis antara rentang dalam awk(ini mengasumsikan Anda tahu berapa banyak garis yang ada):

awk 'NR>1 && NR < 3' file

Atau di Perl:

perl -ne 'print if $.>1 && $.<3' file

Jika Anda tidak tahu berapa banyak garis yang ada, Anda dapat menghitungnya dengan cepat menggunakan grep(perhatikan bahwa ini tidak akan menghitung garis kosong, gunakan juga grep -c '' fileuntuk menghitungnya):

awk -vm="$(grep -c . file2.txt)" 'NR>1 && NR<m' file2.txt

3

Coba solusi ini:

tail -n +2 name_of_file | head -n-1

Kustomisasi

Anda dapat dengan mudah mengadaptasinya untuk menghapus dan mengubah baris pertama +2dari tail;
atau untuk menghapus n baris terakhir mengubah -1dari head.


Solusi ini salah karena mencetak baris pertama.
xhienne

1
@xhienne Maaf, itu kesalahan. Saya menulis 1 bukannya 2 sebagai parameter "tail". Sekarang berhasil, terima kasih! :)
Gabrer

1

Menggunakan awk:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfile: Pengalihan isi inputfileuntuk awk'sstdin
  • > outputfile: Pengalihan isi awk's stdoutuntukoutputfile
  • NR>1: menjalankan tindakan berikut hanya jika jumlah catatan yang diproses lebih besar dari 1
  • {print r}: mencetak konten variabel r
  • {r=$0}: menetapkan konten catatan yang sedang diproses ke variabel r

Jadi pada saat eksekusi pertama awkskrip, blok aksi pertama tidak dieksekusi, sedangkan blok aksi kedua dieksekusi dan konten rekaman ditugaskan ke variabel r; pada eksekusi kedua, blok aksi pertama dieksekusi, dan konten variabel rdicetak (sehingga catatan sebelumnya dicetak); ini memiliki efek mencetak setiap baris yang diproses tetapi yang pertama dan yang terakhir.


Anda tidak termasuk baris pertama. Di NR == 2, Anda mencetak baris input pertama yang disimpan r.
xhienne
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.