Cara menghapus kolom terakhir dari file di Linux

25

Saya ingin menghapus kolom terakhir dari file txt, sementara saya tidak tahu apa nomor kolomnya. Bagaimana saya bisa melakukan ini?

Contoh:

Memasukkan:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

Dan saya ingin hasil saya menjadi:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
zara
sumber
Ada banyak cara untuk melakukan ini..silakan tambahkan contoh dan hasil yang diharapkan dari itu ..
heemayl
@ heemayl ok saya lakukan
zara
Terima kasih..apakah kolom kolom dipisahkan atau ruang dipisahkan?
heemayl
@heemayl space adalah pembatas
zara

Jawaban:

43

Dengan awk:

awk 'NF{NF-=1};1' <in >out

atau:

awk 'NF{NF--};1' <in >out

atau:

awk 'NF{--NF};1' <in >out

Meskipun ini terlihat seperti voodoo, ia berfungsi. Ada tiga bagian untuk masing-masing perintah awk ini.

Yang pertama adalah NF, yang merupakan prasyarat untuk bagian kedua. NFadalah variabel yang berisi jumlah bidang dalam satu baris. Di AWK, semuanya benar jika bukan 0 atau string kosong "". Oleh karena itu, bagian kedua (di mana NFdikurangi) hanya terjadi jika NFtidak 0.

Bagian kedua (baik NF-=1 NF--atau --NF) hanya mengurangi satu dari NFvariabel. Ini mencegah bidang terakhir dari dicetak, karena ketika Anda mengubah bidang (menghapus bidang terakhir dalam kasus ini), awkmembangun kembali $0, menggabungkan semua bidang yang dipisahkan oleh ruang secara default. $0tidak mengandung bidang terakhir lagi.

Bagian terakhir adalah 1. Itu tidak ajaib, hanya digunakan sebagai ungkapan yang berarti true. Jika awkekspresi bernilai true tanpa tindakan yang terkait, awktindakan default adalah print $0.

cuonglm
sumber
@ Jojo: Ah, terima kasih, lupakan --. Sebuah catatan, saat ini, Anda butuhkan ;1untuk mematuhi POSIX.
cuonglm
Naluri awal saya adalah menggunakan for for, tetapi ini jauh lebih ringkas dan pintar.
Sergiy Kolodyazhnyy
5
Perlu dicatat bahwa jika Anda menggunakan pembatas non-default, Anda harus melakukan beberapa perubahan. Dengan asumsi ,adalah pembatas Anda:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
Tn. Llama
1
Efek penurunan NF adalah perilaku yang tidak terdefinisi oleh POSIX - Anda akan mendapatkan output yang berbeda tergantung pada awk yang Anda jalankan. Beberapa awks akan menghapus bidang terakhir seperti yang Anda inginkan, beberapa tidak akan melakukan apa-apa, dan yang lain dapat melaporkan kesalahan sintaks atau yang lainnya.
Ed Morton
16

Menggunakan grepdengan PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Menggunakan GNU sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
heemayl
sumber
1
@ramin Tentu..bisakah Anda menanyakannya sebagai pertanyaan baru (ini adalah bagaimana situs ini bekerja) :)
heemayl
@ramin Apakah itu memberi Anda batasan waktu atau peringatan?
heemayl
katanya ini di luar pertanyaan standar!
zara
@ramin Ok..bolehkan saya menghubungi admin, mungkin mereka dapat membantu Anda dengan itu..tapi apakah Anda memeriksa QA lama tentang pertanyaan Anda? kemungkinan bahwa pertanyaannya sudah ditanyakan dan dijawab ..
heemayl
3
Jangan ajukan pertanyaan super dasar seperti " bagaimana saya bisa mengganti nama file di Linux ". Gunakan Google.
Christoffer Hammarström
11

Menggunakan Perl:

perl -lane '$,=" ";pop(@F);print(@F)' in

Menggunakan rev+ cut:

rev in | cut -d ' ' -f 2- | rev
kos
sumber
5

Menggunakan GNU sed:

sed -r 's/\s+\S+$//' input.txt

Secara umum, ini bekerja dengan BSD sed di OSX, dan juga GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt
Trauma Digital
sumber
1

Jika pembatas selalu berupa char tunggal (jadi dua atau lebih pembatas berturut-turut menunjuk bidang kosong), Anda bisa headmenggunakan baris pertama dari file input Anda, menghitung pembatas ( npembatas berarti jumlah bidang n+1), kemudian gunakan cutuntuk mencetak dari 1bidang st. hingga nbidang ke - th (kedua ke terakhir), mis. dengan input yang dibatasi-tab:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

atau misalnya dengan file csv :

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

Saya akan menjalankan beberapa tolok ukur nanti jika saya punya waktu tetapi dengan input besar saya pikir solusi ini harus lebih cepat daripada solusi lain yang menggunakan regex karena yang satu ini melakukan pemrosesan minimal pada baris pertama untuk mendapatkan no. bidang dan kemudian menggunakan cutyang dioptimalkan untuk pekerjaan ini.

don_crissti
sumber
1

Portable Anda dapat menggunakan salah satu dari ini:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file
Ed Morton
sumber
0

Menggunakan vim:

Buka file dalam vim

vim <filename> 

Pergi ke baris pertama, kalau-kalau kursor ditempatkan di tempat lain.

gg

Buat makro bernama "q" qq, yang pergi ke belakang garis saat ini $, kemudian kembali ke ruang terakhir F(modal F, diikuti oleh SPACE literal) kemudian hapus dari posisi saat ini sampai akhir baris Dturun ke baris berikutnya jdan hentikan perekaman makro dengan q.

qq$F Djq

Sekarang kita bisa mengulang makro kita dengan @quntuk setiap baris.
Kami juga dapat menekan @@untuk mengulangi makro terakhir atau bahkan lebih mudah:

99@q

untuk mengulang makro 99 kali.
Catatan: Jumlahnya harus tidak sama persis dengan garis.

cee
sumber
0

Untuk orang-orang yang memiliki masalah serupa tetapi dengan pemisah lapangan yang berbeda awkmetode ini akan menjaga pemisah lapangan dengan benar:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
htaccess
sumber