Bagaimana cara mendapatkan perilaku terbalik untuk `tail` dan` head`?


55

Apakah ada cara untuk head/ taildokumen dan mendapatkan output terbalik; karena Anda tidak tahu ada berapa baris dalam dokumen?

Yaitu saya hanya ingin mendapatkan semuanya kecuali 2 baris pertama foo.txtuntuk ditambahkan ke dokumen lain.

Jawaban:


57

Anda dapat menggunakan ini untuk menghapus dua baris pertama :

tail -n +3 foo.txt

dan ini untuk menghilangkan dua baris terakhir :

head -n -2 foo.txt

(dengan asumsi file berakhir dengan \nuntuk yang terakhir)


Sama seperti untuk penggunaan standar taildan headoperasi ini tidak merusak. Gunakan >out.txtjika Anda ingin mengarahkan output ke beberapa file baru:

tail -n +3 foo.txt >out.txt

Dalam hal out.txtsudah ada, itu akan menimpa file ini. Gunakan >>out.txtalih-alih >out.txtjika Anda ingin hasilnya ditambahkan out.txt.


3
re "head, ketika file diakhiri dengan \n" .. Ia berfungsi untuk semua bilangan bulat negatif selain -n -0yang tidak mengembalikan apa-apa , sama seperti -n 0(menggunakan: head (GNU coreutils) 7.4) ... Namun ketika sebuah trailing \nhadir, -n -0apakah mencetak seperti yang mungkin diharapkan dari -, yaitu. itu mencetak seluruh file ... Jadi itu berfungsi untuk semua nilai negatif yang tidak nol .. tetapi -0gagal ketika tidak ada trailing\n
Peter.O

@ Fred: Memang aneh ... (sama dengan 8,12 di sini).
Stéphane Gimenez

Apakah operasi ini merusak? Seperti yang saya inginkan untuk menyalin kebalikan dari dua baris pertama dokumen ke yang lain?
chrisjlee

@ Chris: Tidak, mereka hanya mencetak hasilnya pada "output standar" mereka, yang biasanya terhubung ke terminal. Saya telah menambahkan beberapa detail tentang cara mengarahkan output ke beberapa file.
Stéphane Gimenez

7
head -n -2tidak kompatibel dengan POSIX .
l0b0

9

Jika Anda ingin semua kecuali saluran N-1 pertama, hubungi tailnomor yang ada +N. (Angka adalah angka dari baris pertama yang ingin Anda pertahankan, mulai dari 1, yaitu +1 berarti mulai dari atas, +2 berarti lewati satu baris dan seterusnya).

tail -n +3 foo.txt >>other-document

Tidak ada cara mudah dan portabel untuk melewati garis N terakhir. GNU headmemungkinkan head -n +Nsebagai bagian dari tail -n +N. Jika tidak, jika Anda memiliki tac(mis. GNU atau Busybox), Anda dapat menggabungkannya dengan tail:

tac | tail -n +3 | tac

Portable, Anda dapat menggunakan filter awk (belum diuji):

awk -vskip=2 '{
    lines[NR] = $0;
    if (NR > skip) print lines[NR-skip];
    delete lines[NR-skip];
}'

Jika Anda ingin menghapus beberapa baris terakhir dari file besar, Anda dapat menentukan byte offset potongan untuk memotong kemudian melakukan pemotongan dengan dd.

total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"

Anda tidak dapat memotong file di tempat di awal, meskipun jika Anda perlu menghapus beberapa baris pertama dari file besar, Anda dapat memindahkan konten di sekitar .


Pada beberapa sistem (seperti Linux modern), Anda dapat memotong (runtuh) file di tempat di awal, tetapi biasanya hanya dengan jumlah yang kelipatan dari ukuran blok FS (jadi tidak benar-benar berguna dalam kasus ini).
Stéphane Chazelas

3

Dari tailhalaman manual (GNU tail, yaitu):

-n, --lines=K
   output the last K lines, instead of the last 10; or use -n +K to
   output lines starting with the Kth

Dengan demikian, berikut ini harus menambahkan semua kecuali 2 baris pertama somefile.txtke anotherfile.txt:

tail --lines=+3 somefile.txt >> anotherfile.txt

3

Untuk menghapus n baris pertama, GNU sed dapat digunakan. Misalnya jika n = 2

sed -n '1,2!p' input-file

The !berarti "mengecualikan interval ini". Seperti yang dapat Anda bayangkan, hasil yang lebih rumit dapat diperoleh, misalnya

sed -n '3,5p;7p'

itu akan menunjukkan baris 3,4,5,7. Lebih banyak kekuatan berasal dari penggunaan ekspresi reguler, bukan alamat.

Batasannya adalah bahwa nomor garis harus diketahui sebelumnya.


1
Kenapa tidak adil sed 1,2d? Simpler biasanya lebih baik. Juga, tidak ada dalam contoh Anda yang spesifik untuk GNU Sed; perintah Anda semua menggunakan fitur POSIX standar Sed .
Wildcard

1

Anda dapat menggunakan diffuntuk membandingkan output dari head/ tailke file asli dan kemudian menghapus apa yang sama, sehingga mendapatkan kebalikannya.

diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)

1

Sedangkan tail -n +4untuk output file mulai dari baris ke-4 (semua kecuali 3 baris pertama) adalah standar dan portabel, headrekannya ( head -n -3, semua kecuali 3 baris terakhir) tidak.

Mudah dibawa, Anda akan melakukan:

sed '$d' | sed '$d' | sed '$d'

Atau:

sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'

(Waspadalah bahwa pada beberapa sistem di mana sedmemiliki ruang pola ukuran terbatas, yang tidak skala ke nilai besar n).

Atau:

awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'

1
{   head -n2 >/dev/null
    cat  >> other_document
}   <infile

Jika <infilefile biasa, lseek()-able, maka ya, tentu saja, silakan saja. Di atas adalah konstruk yang sepenuhnya didukung POSIXly.


0

Pendekatan saya mirip dengan Gilles tapi saya malah membalikkan file dengan kucing dan pipa itu dengan perintah kepala.

tac -r thefile.txt | head thisfile.txt (menggantikan file)


0

Semoga saya mengerti dengan jelas kebutuhan Anda.

Anda memiliki beberapa cara untuk menyelesaikan permintaan Anda:

tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd

Di mana / etc / passwd adalah file Anda

Solusi ke-2 mungkin bermanfaat jika Anda memiliki file besar:

my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"

0

Solusi untuk BSD (macOS):

Hapus 2 baris pertama:

tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

Hapus 2 baris terakhir:

head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

... tidak terlalu elegan tetapi menyelesaikan pekerjaan!

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.