@Jefromi - juga cuttidak memiliki ekspresi reguler sebelum {}tindakan, dan kemudian jauh lebih bodoh dengan pembatas bidang (jumlah spasi variabel?), Dan Anda harus menentukannya secara manual. Saya pikir OP ingin mendengar tentang beberapa shift Nperintah, yang tidak ada. Yang paling dekat adalah $1="";$2="";(...);print}, tetapi dalam kasus saya ini meninggalkan beberapa spasi utama (mungkin pemisah).
Jawaban EdMorton tidak berhasil untuk saya (bash 4.1.2 (1) -release, GNU Awk 3.1.7 atau bash 3.2.25 (1) -release, GNU Awk 3.1.5) tetapi ditemukan di sini dengan cara lain:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
1
@elysch no, itu tidak akan berfungsi secara umum, itu hanya tampak berfungsi dengan beberapa nilai input tertentu. Lihat komentar yang saya tambahkan di bawah komentar Anda di bawah jawaban saya.
Ed Morton
1
Hai @doyok Jawaban saya adalah yang pertama. Dalam jawaban asli saya, saya menjelaskan mengapa jawaban lain tidak benar (spasi tambahan di depan atau di belakang). Beberapa orang telah mengusulkan peningkatan dalam komentar. Kami telah meminta OP untuk memilih jawaban yang lebih benar, dan dia telah memilih jawaban saya. Setelah beberapa kontributor lain mengedit jawaban saya untuk referensi jawaban di sana (lihat sejarah). Apakah sudah jelas bagi Anda? Apa saran Anda untuk meningkatkan pemahaman jawaban saya? Cheers ;-)
olibre
1
Anda benar sekali dan saya sangat menyesal atas kesalahpahaman saya. Saya membaca cepat untuk menjawab dan tidak memperhatikan jawaban asli Anda (ya, saya membaca terlalu cepat). +1 untuk jawabannya sendiri menggunakan trik bagus untuk mengulang hingga NF-1 dan kemudian mencetak elemen terakhir untuk menghindari spasi ekstra. Dan maaf lagi! (akan menghapus komentar saya dalam satu atau dua hari, untuk mencegah kesalahpahaman dari pembaca di masa mendatang).
fedorqui 'JADI berhenti merugikan'
1
Saya akan menggunakan beberapa jenis tajuk: <jawaban Anda> dan kemudian aturan horizontal diikuti dengan judul besar "perbandingan jawaban lainnya". Jika tidak, pindahkan perbandingan ini ke jawaban lain, karena tampaknya orang cenderung lebih memilih jawaban singkat dalam visi "
mungkin lebih baik menggunakan "NF" daripada "13" pada contoh terakhir.
glenn jackman
2
2 skenario terserah OP untuk memutuskan. jika 13 adalah kolom terakhir, menggunakan NF sudah cukup. Jika tidak, menggunakan 13 sudah tepat.
ghostdog74
3
2nd perlu menghapus 3 salinan OFS dari awal $ 0. Yang ketiga akan lebih baik dengan printf "%s ",$i, karena Anda tidak tahu apakah $imungkin mengandung %satau sejenisnya. Tapi itu akan mencetak ruang ekstra di akhir.
Ini bagus karena betapa dinamisnya itu. Anda dapat menambahkan kolom di akhir dan tidak menulis ulang skrip Anda.
MinceMan
1
Ini menunjukkan masalah sebenarnya yang coba Anda tangani, tetapi lakukan yang sebaliknya. Bagaimana dengan mencetak dari bidang ke-100? Catatan untuk menyebutkan Anda tidak berurusan dengan NFsehingga Anda meninggalkan memimpin OFS.
Chris Seymour
24
Cara yang benar untuk melakukannya adalah dengan interval RE karena memungkinkan Anda dengan mudah menyatakan berapa banyak bidang yang akan dilewati, dan mempertahankan jarak antar bidang untuk bidang yang tersisa.
misalnya untuk melewati 3 bidang pertama tanpa mempengaruhi jarak antara bidang yang tersisa mengingat format input yang sepertinya kita bahas dalam pertanyaan ini adalah:
Jika Anda memiliki FS yang merupakan RE yang tidak dapat Anda negasikan dalam kumpulan karakter, Anda dapat mengubahnya menjadi satu karakter terlebih dahulu (RS ideal jika itu adalah karakter tunggal karena RS TIDAK DAPAT muncul dalam bidang, jika tidak pertimbangkan LANGGANAN), kemudian terapkan subsitusi interval RE, lalu ubah ke OFS. misalnya jika rantai "." memisahkan bidang:
Kemudian Anda memiliki masalah yang sama dengan semua solusi berbasis loop yang menetapkan ulang bidang - FS diubah menjadi OFS. Jika itu menjadi masalah, Anda perlu melihat ke fungsi patsplit () GNU awks.
Tidak berfungsi untuk saya (bash 4.1.2 (1) -release, GNU Awk 3.1.7 atau bash 3.2.25 (1) -release, GNU Awk 3.1.5) tetapi ditemukan di sini dengan cara lain:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
2
Tidak, itu akan gagal jika $ 1 atau $ 2 berisi string $ 3 yang disetel. Coba, misalnya echo ' That is a test' | awk '{print substr($0, index($0,$3))}'dan Anda akan menemukan bahwa a$ 3 cocok dengan abagian Thatdalam $ 1. Dalam versi yang sangat lama dari gawk seperti yang Anda miliki, Anda perlu mengaktifkan interval RE dengan bendera --re-interval.
Ed Morton
2
Anda benar, tidak menyadarinya. Ngomong-ngomong, sangat hargai komentar Anda. Berkali-kali ingin menggunakan regex dengan "{}" untuk menentukan jumlah elemen dan tidak pernah melihat "--re-interval" pada pria itu. 1 untuk Anda.
elysch
1
1adalah kondisi sebenarnya dan karenanya memanggil tindakan awk default untuk mencetak rekaman saat ini.
Ed Morton
1
saya tidak tahu bagaimana kanonisnya tetapi saya menambahkan jawaban sekarang.
Ed Morton
10
Hampir semua jawaban saat ini menambahkan spasi di depan, spasi tambahan, atau masalah pemisah lainnya. Untuk memilih dari bidang keempat di mana pemisahnya adalah spasi dan pemisah keluaran adalah satu spasi menggunakan awkakan:
Atau untuk membuatnya di baris yang sama, tetapkan $ 3 ke $ 1, dll. Dan kemudian ubah NF ke jumlah kolom yang tepat. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr
Hai @larsr. Baris perintah yang Anda usulkan adalah satu-satunya jawaban yang benar. Semua jawaban lainnya menambahkan spasi ekstra (di depan atau di belakang). Silakan kirim baris perintah Anda dalam jawaban baru, saya akan memilihnya ;-)
olibre
1
Hai @sudo_O, saya berbicara dengan @larsr, tentang baris perintah yang dia usulkan dalam komentarnya. Saya menghabiskan sekitar lima menit sebelum mencari tahu quiproco (kesalahpahaman). Saya setuju, jawaban @Vetsin menyisipkan baris baru ( ORS) di antara bidang. Bravo atas inisiatif Anda (saya suka jawaban Anda). Cheers
olibre
3
Cara lain untuk menghindari penggunaan pernyataan cetak:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
Dalam kondisi awk ketika kondisi true print adalah tindakan default.
1 untuk solusi serupa ... Tetapi ini mungkin memiliki masalah kinerja jika filebesar (> 10-30KiB). Untuk file besar, awksolusinya bekerja lebih baik.
TrueY
3
Opsi 1 hingga 3 memiliki masalah dengan banyak spasi (tapi sederhana). Itulah alasan untuk mengembangkan opsi 4 dan 5, yang memproses banyak ruang putih tanpa masalah. Tentu saja, jika opsi 4 atau 5 digunakan dengan n=0keduanya akan mempertahankan spasi di depan sebagai n=0cara tidak ada pemisahan.
Pilihan 1
Solusi pemotongan sederhana (bekerja dengan pembatas tunggal):
$ echo '1 2 3 4 5 6 7 8'| cut -d' '-f4-45678
pilihan 2
Memaksa penghitungan ulang awk terkadang menyelesaikan masalah (berfungsi dengan beberapa versi awk) dari spasi tambahan yang ditambahkan:
CATATAN: The "^ [" FS "] *" untuk menerima masukan dengan spasi di depan.
Pilihan 5
Sangat mungkin untuk membangun solusi yang tidak menambahkan spasi tambahan di depan atau di belakang, dan mempertahankan spasi kosong yang ada menggunakan fungsi gensubdari GNU awk, karena ini:
Hai BZ Jawaban Anda bagus. Tetapi Opsi 3 tidak bekerja pada string yang dimulai dengan spasi (misalnya " 1 2 3 4 5 6 7 8 "). Opsi 4 bagus tetapi tinggalkan spasi di depan menggunakan string yang dimulai dengan spasi. Apakah menurut Anda jika ini bisa diperbaiki? Anda dapat menggunakan perintah echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'untuk memverifikasi spasi di depan / tengah / di belakang ... Cheers;)
olibre
Hai @olib. Bahwa opsi 3 gagal dengan spasi putih adalah alasan untuk mengembangkan opsi 4 dan 5. Opsi 4 hanya menyisakan spasi di depan jika input memilikinya dan n disetel ke 0 (n = 0). Itu saya yakin adalah jawaban yang benar ketika tidak ada pilihan bidang (tidak ada yang memperbaiki IMO). Bersulang.
Baiklah. Terima kasih atas informasi tambahannya :-) Harap perbaiki jawaban Anda dengan memberikan info tambahan ini :-) Salam
olibre
Sempurna :-) Sayang sekali pengguna Anda dinonaktifkan :-(
olibre
1
Cut memiliki tanda --complement yang membuatnya mudah (dan cepat) untuk menghapus kolom. Sintaks yang dihasilkan analog dengan apa yang ingin Anda lakukan - membuat solusi lebih mudah dibaca / dipahami. Pelengkap juga berfungsi untuk kasus di mana Anda ingin menghapus kolom yang tidak bersebelahan.
Bisakah Anda menjelaskan lebih lanjut jawaban Anda?
Zulu
Apakah hasil edit di atas membantu dalam pemahaman? Intinya adalah menggunakan bendera pelengkap potong. Solusinya harus implementasi yang lebih cepat dan lebih ringkas daripada solusi berbasis AWK atau perl. Juga, kolom sewenang-wenang dapat dipotong.
Michael Kembali
1
Solusi Perl yang tidak menambahkan spasi kosong di depan atau di belakang:
Karena saya kesal dengan jawaban pertama yang sangat disukai tetapi salah, saya menemukan cukup banyak untuk menulis balasan di sana, dan di sini jawaban yang salah ditandai seperti itu, ini sedikit saya. Saya tidak suka solusi yang diusulkan karena saya tidak melihat alasan untuk membuat jawaban menjadi begitu rumit.
Saya memiliki log di mana setelah $ 5 dengan alamat IP bisa lebih banyak teks atau tidak ada teks. Saya membutuhkan semuanya, mulai dari alamat IP hingga akhir baris jika ada sesuatu setelah $ 5. Dalam kasus saya, ini sebenarnya dengan program awk, bukan awk oneliner jadi awk harus menyelesaikan masalah. Ketika saya mencoba untuk menghapus 4 bidang pertama menggunakan jawaban lama yang terlihat bagus dan paling banyak disukai tetapi sepenuhnya salah:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'
itu mengeluarkan tanggapan yang salah dan tidak berguna (saya menambahkan [] untuk menunjukkan):
[37.244.182.218 one two three]
Sebaliknya, jika kolom memiliki lebar tetap hingga titik potong dan awk diperlukan, jawaban yang benar dan cukup sederhana adalah:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{printf "[%s]\n", substr($0,28)}'
Hasilnya akan %-5sdisejajarkan sebagai kolom dengan lebar 5 karakter; jika ini tidak cukup, tambah jumlahnya, atau gunakan %s(dengan spasi) sebagai gantinya jika Anda tidak peduli tentang perataan.
Solusi berbasis AWK printf yang menghindari% masalah, dan unik karena tidak mengembalikan apa-apa (tidak ada karakter kembali) jika ada kurang dari 4 kolom untuk dicetak:
cut -f3-
?cut
tidak memiliki ekspresi reguler sebelum{}
tindakan, dan kemudian jauh lebih bodoh dengan pembatas bidang (jumlah spasi variabel?), Dan Anda harus menentukannya secara manual. Saya pikir OP ingin mendengar tentang beberapashift N
perintah, yang tidak ada. Yang paling dekat adalah$1="";$2="";(...);print}
, tetapi dalam kasus saya ini meninggalkan beberapa spasi utama (mungkin pemisah).Jawaban:
Solusi yang tidak menambahkan spasi kosong di depan atau di belakang :
Sudo_O mengusulkan perbaikan yang elegan dengan menggunakan operator terner
NF?ORS:OFS
EdMorton memberikan solusi untuk menjaga spasi putih asli antar bidang:
BinaryZebra juga menyediakan dua solusi luar biasa:
(solusi ini bahkan mempertahankan spasi tertinggal dari string asli)
Solusi yang diberikan oleh larsr di komentar hampir benar:
Ini adalah versi solusi larsr yang diperbaiki dan diparameterisasi :
Semua jawaban lain sebelum Sep-2013 bagus, tetapi tambahkan spasi tambahan:
Contoh jawaban menambahkan spasi tambahan :
Contoh jawaban yang menambahkan spasi tambahan
sumber
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
sumber
OFS
karena Anda tidak berurusan dengan,NF
yaitu ruang terdepan dalam catatan.gunakan potongan
atau jika Anda bersikeras pada awk dan $ 13 adalah kolom terakhir
lain
sumber
printf "%s ",$i
, karena Anda tidak tahu apakah$i
mungkin mengandung%s
atau sejenisnya. Tapi itu akan mencetak ruang ekstra di akhir.Coba ini:
sumber
NF
sehingga Anda meninggalkan memimpinOFS
.Cara yang benar untuk melakukannya adalah dengan interval RE karena memungkinkan Anda dengan mudah menyatakan berapa banyak bidang yang akan dilewati, dan mempertahankan jarak antar bidang untuk bidang yang tersisa.
misalnya untuk melewati 3 bidang pertama tanpa mempengaruhi jarak antara bidang yang tersisa mengingat format input yang sepertinya kita bahas dalam pertanyaan ini adalah:
Jika Anda ingin mengakomodasi spasi utama dan spasi tidak kosong, tetapi sekali lagi dengan FS default, maka:
Jika Anda memiliki FS yang merupakan RE yang tidak dapat Anda negasikan dalam kumpulan karakter, Anda dapat mengubahnya menjadi satu karakter terlebih dahulu (RS ideal jika itu adalah karakter tunggal karena RS TIDAK DAPAT muncul dalam bidang, jika tidak pertimbangkan LANGGANAN), kemudian terapkan subsitusi interval RE, lalu ubah ke OFS. misalnya jika rantai "." memisahkan bidang:
Tentunya jika OFS adalah karakter tunggal DAN tidak dapat muncul di bidang masukan, Anda dapat menguranginya menjadi:
Kemudian Anda memiliki masalah yang sama dengan semua solusi berbasis loop yang menetapkan ulang bidang - FS diubah menjadi OFS. Jika itu menjadi masalah, Anda perlu melihat ke fungsi patsplit () GNU awks.
sumber
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
echo ' That is a test' | awk '{print substr($0, index($0,$3))}'
dan Anda akan menemukan bahwaa
$ 3 cocok dengana
bagianThat
dalam $ 1. Dalam versi yang sangat lama dari gawk seperti yang Anda miliki, Anda perlu mengaktifkan interval RE dengan bendera--re-interval
.1
adalah kondisi sebenarnya dan karenanya memanggil tindakan awk default untuk mencetak rekaman saat ini.Hampir semua jawaban saat ini menambahkan spasi di depan, spasi tambahan, atau masalah pemisah lainnya. Untuk memilih dari bidang keempat di mana pemisahnya adalah spasi dan pemisah keluaran adalah satu spasi menggunakan
awk
akan:Untuk parameter bidang awal yang dapat Anda lakukan:
Dan juga kolom penutup:
sumber
Memasukkan
Keluaran
sumber
sumber
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
ORS
) di antara bidang. Bravo atas inisiatif Anda (saya suka jawaban Anda). CheersCara lain untuk menghindari penggunaan pernyataan cetak:
Dalam kondisi awk ketika kondisi true print adalah tindakan default.
sumber
awk '{$1=$2=$3=""}sub("^"OFS"+","")' file
seperti OFS apa yang tersisa setelah mengubah konten $ 1, $ 2, dan $ 3.Saya tidak percaya tidak ada yang menawarkan cangkang biasa:
sumber
file
besar (> 10-30KiB). Untuk file besar,awk
solusinya bekerja lebih baik.Opsi 1 hingga 3 memiliki masalah dengan banyak spasi (tapi sederhana). Itulah alasan untuk mengembangkan opsi 4 dan 5, yang memproses banyak ruang putih tanpa masalah. Tentu saja, jika opsi 4 atau 5 digunakan dengan
n=0
keduanya akan mempertahankan spasi di depan sebagain=0
cara tidak ada pemisahan.Pilihan 1
Solusi pemotongan sederhana (bekerja dengan pembatas tunggal):
pilihan 2
Memaksa penghitungan ulang awk terkadang menyelesaikan masalah (berfungsi dengan beberapa versi awk) dari spasi tambahan yang ditambahkan:
Opsi 3
Mencetak setiap bidang yang diformat dengan
printf
akan memberi lebih banyak kontrol:Namun, semua jawaban sebelumnya mengubah semua FS antar bidang menjadi OFS. Mari kita buat beberapa solusi untuk itu.
Pilihan 4
Perulangan dengan sub untuk menghapus bidang dan pembatas lebih portabel, dan tidak memicu perubahan FS menjadi OFS:
CATATAN: The "^ [" FS "] *" untuk menerima masukan dengan spasi di depan.
Pilihan 5
Sangat mungkin untuk membangun solusi yang tidak menambahkan spasi tambahan di depan atau di belakang, dan mempertahankan spasi kosong yang ada menggunakan fungsi
gensub
dari GNU awk, karena ini:Ini juga dapat digunakan untuk menukar daftar bidang dengan hitungan
n
:Tentu saja, dalam kasus seperti itu, OFS digunakan untuk memisahkan kedua bagian garis, dan ruang putih di belakang bidang masih dicetak.
Note1:
["FS"]*
digunakan untuk memungkinkan spasi di baris input.sumber
" 1 2 3 4 5 6 7 8 "
). Opsi 4 bagus tetapi tinggalkan spasi di depan menggunakan string yang dimulai dengan spasi. Apakah menurut Anda jika ini bisa diperbaiki? Anda dapat menggunakan perintahecho " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
untuk memverifikasi spasi di depan / tengah / di belakang ... Cheers;)Cut memiliki tanda --complement yang membuatnya mudah (dan cepat) untuk menghapus kolom. Sintaks yang dihasilkan analog dengan apa yang ingin Anda lakukan - membuat solusi lebih mudah dibaca / dipahami. Pelengkap juga berfungsi untuk kasus di mana Anda ingin menghapus kolom yang tidak bersebelahan.
sumber
Solusi Perl yang tidak menambahkan spasi kosong di depan atau di belakang:
@F
Larik perl autosplit dimulai pada indeks0
sementara bidang awk dimulai dengan$1
Solusi Perl untuk data yang dipisahkan koma:
Solusi Python:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file
sumber
Bagi saya, solusi yang paling ringkas dan sesuai untuk permintaan tersebut adalah
Dan jika Anda memiliki lebih banyak baris untuk diproses seperti misalnya file foo.txt , jangan lupa untuk mengatur ulang i ke 0:
Terima kasih forum Anda.
sumber
Karena saya kesal dengan jawaban pertama yang sangat disukai tetapi salah, saya menemukan cukup banyak untuk menulis balasan di sana, dan di sini jawaban yang salah ditandai seperti itu, ini sedikit saya. Saya tidak suka solusi yang diusulkan karena saya tidak melihat alasan untuk membuat jawaban menjadi begitu rumit.
Saya memiliki log di mana setelah $ 5 dengan alamat IP bisa lebih banyak teks atau tidak ada teks. Saya membutuhkan semuanya, mulai dari alamat IP hingga akhir baris jika ada sesuatu setelah $ 5. Dalam kasus saya, ini sebenarnya dengan program awk, bukan awk oneliner jadi awk harus menyelesaikan masalah. Ketika saya mencoba untuk menghapus 4 bidang pertama menggunakan jawaban lama yang terlihat bagus dan paling banyak disukai tetapi sepenuhnya salah:
itu mengeluarkan tanggapan yang salah dan tidak berguna (saya menambahkan [] untuk menunjukkan):
Sebaliknya, jika kolom memiliki lebar tetap hingga titik potong dan awk diperlukan, jawaban yang benar dan cukup sederhana adalah:
yang menghasilkan keluaran yang diinginkan:
sumber
Saya sudah menemukan kemungkinan lain ini, mungkin bisa berguna juga ...
awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file
Catatan: 1. Untuk data tabel dan dari kolom $ 1 sampai $ 14
sumber
Gunakan potongan:
misal: Jika sudah
file1
berisi:car.is.nice.equal.bmw
Jalankan:
cut -d . -f1,3 file1
akan mencetakcar.is.nice
sumber
Ini tidak terlalu jauh dari beberapa jawaban sebelumnya, tetapi memecahkan beberapa masalah:
cols.sh
:Yang sekarang dapat Anda panggil dengan argumen yang akan menjadi kolom awal:
Atau:
Ini 1-indeks; jika Anda lebih suka tidak diindeks, gunakan
i=s + 1
saja.Selain itu, jika Anda ingin memiliki argumen untuk indeks awal dan indeks akhir, ubah file menjadi:
Sebagai contoh:
Hasilnya akan
%-5s
disejajarkan sebagai kolom dengan lebar 5 karakter; jika ini tidak cukup, tambah jumlahnya, atau gunakan%s
(dengan spasi) sebagai gantinya jika Anda tidak peduli tentang perataan.sumber
Solusi berbasis AWK printf yang menghindari% masalah, dan unik karena tidak mengembalikan apa-apa (tidak ada karakter kembali) jika ada kurang dari 4 kolom untuk dicetak:
Pengujian:
sumber