Bagaimana cara mencetak semua kolom setelah nomor tertentu menggunakan awk?

90

Pada shell, saya pipa ke awk ketika saya membutuhkan kolom tertentu.

Ini mencetak kolom 9, misalnya:

... | awk '{print $9}'

Bagaimana cara memberi tahu awk untuk mencetak semua kolom termasuk dan setelah kolom 9 , bukan hanya kolom 9?

Lazer
sumber

Jawaban:

83
awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'
Amadan
sumber
3
beberapa perbaikan kecil:awk -v N=9 '{sep=""; for (i=N; i<=NF; i++) {printf("%s%s",sep,$i); sep=OFS}; printf("\n")}'
glenn jackman
Terima kasih @glenn, itu memang sedikit lebih umum. Bagaimanapun - saya pasti setuju akan lebih baik menggunakan cutatau perluntuk ini. Gunakan ini hanya jika Anda benar-benar bersikeras untuk memilikinya awk.
Amadan
1
@SiegeX: Ini tidak menambahkan byte NUL, meninggalkan FS di antara setiap bidang kosong.
Dijeda sampai pemberitahuan lebih lanjut.
1
Silakan lihat jawaban @ Ascherer untuk keanggunan.
3
@veryhungrymike: Keanggunan itu bagus, tapi saya lebih suka benar. : p
Amadan
68

Ketika Anda ingin melakukan berbagai bidang, awktidak benar-benar memiliki cara langsung untuk melakukan ini. Saya akan merekomendasikan cutsebagai gantinya:

cut -d' ' -f 9- ./infile

Edit

Menambahkan pembatas bidang spasi karena defaultnya adalah tab. Terima kasih kepada Glenn karena telah menunjukkan hal ini

SiegeX
sumber
15
Satu hal tentang cut adalah bahwa ia menggunakan pembatas tertentu (tab secara default), di mana awk menggunakan "spasi". Dengan pemotongan, 2 tab berturut-turut membatasi bidang kosong.
glenn jackman
1
Seperti yang ditunjukkan @glennjackman, pembatas awk adalah "spasi" (berapa pun jumlahnya). Jadi, menyetel pembatas potong ke satu spasi tidak akan cocok dengan perilaku juga. sayangnya loop adalah yang terbaik yang bisa dilakukan, jadi sepertinya.
poncha
Yang ini tidak berfungsi dengan baik. Coba perintahnya find . | xargs ls -l | cut -d' ' -f 9-. Untuk beberapa alasan spasi ganda juga dihitung. Contoh: lrwxrwxrwx 1 me me 21 Dec 12 00:00 ./file_a lrwxrwxrwx 1 me me 64 Dec 6 00:06 ./file_bakan menghasilkan./file_a 00:06 ./file_b
Marco Pashkov
@MarcoPashkov harap jelaskan Hal ini tidak berfungsi dengan baik , terutama mengingat Anda menggunakan kode yang sama persis di pipeline Anda. Omong-omong, Anda tidak
SiegeX
cut tidak melakukan pekerjaan di sini. Misalnya, jika input Anda adalah "foo bar" (spasi tunggal) untuk satu baris, dan "foo ___ bar" (yaitu beberapa spasi, tetapi SO terlalu pintar untuk menampilkannya) untuk baris lainnya, cut akan memprosesnya secara berbeda.
UKMonkey
54
awk '{print substr($0, index($0,$9))}'

Edit : Perhatikan, ini tidak berfungsi jika ada bidang sebelum yang kesembilan berisi nilai yang sama dengan yang kesembilan.

Ascherer
sumber
3
yang ini luar biasa!
10
@veryhungrymike: ... dan tidak berfungsi jika ada bidang sebelum kesembilan berisi nilai yang sama dengan yang kesembilan.
Amadan
6
Mungkin karena kalimat klasik "semoga file Anda tidak mengalami masalah itu". Ini adalah total no-no in s / w engineering untuk menyatakan: "kami tidak akan membuang waktu termasuk pengecekan kesalahan untuk masukan misalnya nilai negatif, karena 'kami berharap pengguna akan cukup cerdas untuk tidak mencobanya, merusak alat kami '". HA HA HA! Selalu senang mendengar ini! (Saya suka selera humor yang bagus) Yah, karena orang idiot memang ada, itu adalah tugas pengembang untuk membuat barang-barangnya tahan terhadap orang bodoh ! Dari pada "mengharapkan kebaikan dalam diri manusia". Itu lebih merupakan sikap yang diharapkan oleh para filsuf, bukan para insinyur ... LOL
kesalahan sintaksis
3
Saya tidak mengatakan untuk tidak memeriksa kesalahan, tetapi jika Anda tahu Anda tidak akan mengalami masalah, maka solusi ini baik-baik saja, seperti yang saya nyatakan. Tapi terima kasih atas downvote @syntaxerror yang tidak perlu. Solusi ini akan berfungsi untuk beberapa orang, karena (saat ini) 19 suara positif akan ditampilkan, tetapi jika tidak, jangan gunakan untuk solusi Anda. Ada banyak cara untuk mengatasi masalah OP.
Ascherer
1
Jika Anda menggunakan awk pada baris perintah dalam pekerjaan sehari-hari Anda, ini jelas merupakan solusi yang Anda inginkan. Apakah tidak jelas? Pemeriksaan kesalahan, dll, tidak terlalu penting dalam hal itu karena Anda mengetiknya & dapat menangkap hal-hal semacam ini sebelum Anda menekan enter (secara pribadi, saya tidak berpikir awk harus digunakan untuk hal lain, itu sebabnya kami Saya punya perl, python, tcl, dan sekitar 100+ bahasa skrip lainnya, lebih baik, lebih cepat, dan tidak terlalu mengganggu!) 'Tentu saja mungkin saya memberi kredit terlalu banyak kepada sesama pengembang perangkat lunak dan mereka benar-benar membutuhkan pemeriksaan kesalahan bahkan pada hal-hal yang mereka ketik dengan cepat (??)
osirisgothra
11
sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

Alih-alih berurusan dengan spasi putih lebar variabel, ganti semua spasi putih sebagai spasi tunggal. Kemudian gunakan sederhana cutdengan bidang yang diminati.

Itu tidak menggunakan awk jadi tidak erat tetapi sepertinya sesuai diberikan jawaban / komentar lain.

Beberapa Bodoh
sumber
1
Tolong buat jawaban Anda lebih banyak, jika tidak posting ini sebagai komentar untuk pertanyaan.
Alper Turan
Ini sangat ideal untuk ps faux | digunakan. Jangan pernah takut mengakui alat XYZ bukan yang paling tepat.
kevinf
10

Umumnya perl menggantikan awk / sed / grep et. al., dan banyak lebih portabel (serta menjadi pisau lipat yang lebih baik).

perl -lane 'print "@F[8..$#F]"'

Timtowtdi berlaku tentu saja.

bobbogo.dll
sumber
Anda perlu menambahkan opsi baris perintah -l, atau menambahkan \nke pernyataan cetak.
glenn jackman
@ Glenn Jackman: Mungkin. Tidak diperlukan jika bagian dari pesan lain, atau ditugaskan ke variabel dll. Sejauh "lebih baik" berjalan, perl pasti terlihat lebih baik di yang kecil. Bisa terlihat sangat tidak rapi di tempat yang besar memang.
bobbogo
Jangan salah paham, saya suka Perl. Aku suka canggung untuk apa adanya.
glenn jackman
Perangkat saya yang disematkan tidak disertakan dengan Perl, tetapi memiliki awk.
Sepero
Downvoting karena pertanyaannya menanyakan bagaimana melakukan ini di awk, bukan perl, ruby, java, python, bash.
Tom Harrison
3
awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

Ini memotong apa yang ada sebelum bidang yang diberikan nr., N, dan mencetak semua sisa baris, termasuk bidang nr.N dan mempertahankan jarak asli (tidak memformat ulang). Tidak masalah jika string bidang muncul juga di tempat lain dalam baris, yang merupakan masalah dengan jawaban Ascherer.

Tentukan fungsi:

fromField () { 
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

Dan gunakan seperti ini:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost   

Output mempertahankan semuanya, termasuk spasi tambahan Untuk N = 0 ia mengembalikan seluruh baris, sebagaimana adanya, dan untuk n> NF string kosong

Robert Vila
sumber
Ini ide yang bagus. Itu tidak cukup berfungsi pada Mac saat ini menggunakan gawk biasa, karena $ 0 runtuh. Cara memperbaikinya adalah menyetel variabel ke $ 0 sebagai langkah pertama, seperti: '{s = $ 0; ... cetak substr (s, indeks (s, m) +1}
joelparkerhenderson
1

Berikut adalah contoh ls -lkeluarannya:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

Solusi saya untuk mencetak postingan apa pun $9adalahawk '{print substr($0, 61, 50)}'

rickydj.dll
sumber
0
ruby -lane 'print $F[3..-1].join(" ")' file
kurumi
sumber
0

Untuk menampilkan 3 kolom pertama dan mencetak kolom lainnya, Anda dapat menggunakan:

awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename

di mana $ 1 $ 2 $ 3 adalah 3 bidang pertama.

Raymond C Borges Hink
sumber
0
function print_fields(field_num1, field_num2){
    input_line = $0

    j = 1;
    for (i=field_num1; i <= field_num2; i++){
        $(j++) = $(i);

    }
    NF = field_num2 - field_num1 + 1;
    print $0

    $0 = input_line
}
msol01
sumber
0

Menggunakan cut daripada awk dan mengatasi masalah dengan mencari tahu kolom mana untuk memulai dengan menggunakan perintah -c character cut.

Di sini saya katakan, berikan semua kecuali 49 karakter pertama dari keluaran.

 ls -l /some/path/*/* | cut -c 50-

Itu /*/*/ akhir perintah ls mengatakan tunjukkan apa yang ada di subdirektori juga.

Anda juga dapat menarik rentang karakter tertentu secara (dari halaman manual yang dipotong). Misalnya, tunjukkan nama dan waktu login dari pengguna yang sedang login:

       who | cut -c 1-16,26-38
Joe
sumber