it-swarm-id.com

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

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

Yaitu. Saya hanya ingin mendapatkan semuanya kecuali 2 baris pertama foo.txt untuk menambahkan ke dokumen lain.

57
chrisjlee

Anda dapat menggunakan ini untuk menghapus pertama dua baris:

tail -n +3 foo.txt

dan ini untuk menghapus terakhir dua baris:

head -n -2 foo.txt

(dengan asumsi file berakhir dengan \n untuk yang terakhir)


Sama seperti untuk penggunaan standar tail dan head operasi ini tidak merusak. Gunakan >out.txt jika Anda ingin mengarahkan output ke beberapa file baru:

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

Dalam kasus ini out.txt sudah ada, itu akan menimpa file ini. Gunakan >>out.txt dari pada >out.txt jika Anda ingin hasilnya ditambahkan ke out.txt.

59

Jika Anda ingin semua kecuali baris N-1 pertama, panggil tail dengan jumlah baris +N. (Angka adalah angka dari baris pertama yang ingin Anda pertahankan, mulai dari 1, mis. +1 berarti mulai dari atas, +2 berarti melewati satu baris dan seterusnya).

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

Tidak ada cara mudah dan portabel untuk melewati garis N terakhir. GNU head memungkinkan head -n +N sebagai 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 bisa memindahkan konten di sekitar .

Dari halaman manual tail (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.txt hingga anotherfile.txt:

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

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

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

! berarti "kecualikan 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 alih-alih alamat.

Batasannya adalah bahwa nomor garis harus diketahui sebelumnya.

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

Jika <infile adalah file biasa, lseek() - bisa, maka ya, tentu saja, silakan saja. Di atas adalah konstruk yang sepenuhnya didukung POSIX.

2
mikeserv

Sementara tail -n +4 untuk menampilkan file mulai dari baris ke-4 (semua kecuali 3 baris pertama) adalah standar dan portabel, head rekanan (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 sed memiliki ruang pola ukuran terbatas, yang tidak menskala ke nilai besar n).

Atau:

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

Anda dapat menggunakan diff untuk membandingkan output dari head/tail ke file asli dan kemudian menghapus apa yang sama, sehingga mendapatkan kebalikannya.

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

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
Abe

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!

0
spectrum

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 berguna 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
Mathieu Coavoux