awk menetapkan beberapa variabel sekaligus

9

Saya mencoba menarik dua nilai numerik dari string dan menetapkannya ke variabel menggunakan awk( gawkadalah apa yang saya gunakan khusus). Saya ingin menarik nomor versi utama dan kecil dari string versi tmux ke dalam awkvariabel, misalnya:

  • masukan tmux 2.8:; maj == 2danmin == 8
  • masukan tmux 1.9a:; maj == 1danmin == 9
  • masukan tmux 2.10:; maj == 2danmin == 10

Dengan asumsi input saya berasal dari tmux -Vpada stdin, saat ini saya memiliki yang berikut:

tmux -V | awk '{
                  maj = +gensub(/([0-9]+)\..*/, "\\1", "g", $2);
                  min = +gensub(/.*\.([0-9]+).*/, "\\1", "g", $2);
                  # ...do something with maj and min...
               }'

Ini berfungsi, tetapi karena banyak pengguna tmux tahu, menggunakan if-shelldalam .tmux.conffile (di mana saya berharap untuk menggunakan hal ini) dapat dengan mudah mengarah ke garis yang sangat panjang dalam file konfigurasi, jadi saya bertanya-tanya apakah ada cara untuk menggabungkan kedua variabel ini tugas menjadi satu pernyataan untuk menghemat ruang ... atau cara lain untuk mendapatkan dua variabel ini dari input dan menghemat ruang.

Saya sedang memikirkan sesuatu seperti:

awk '{ maj, min = +gensub(/([0-9]+)\.([0-9]+).*/, "\\1 \\2", "g", $2); }'

... seperti di Python, tetapi sintaks tertentu tidak ada di awk. Apakah ada hal lain yang mungkin?

Perhatikan bahwa keterbacaan sebenarnya bukan masalah, hanya panjang.

villapx
sumber

Jawaban:

9

Perhatikan bahwa gensubini adalah gawkekstensi, itu tidak akan berfungsi dengan awkimplementasi lainnya . Juga perhatikan bahwa +operator unary tidak memaksa konversi numerik di semua awkimplementasi, menggunakan + 0lebih portabel.

Di sini Anda dapat melakukannya:

tmux -V | awk -F '[ .]' '{maj = $2+0; min = $3+0; print maj, min}'

Jika Anda tidak keberatan menggunakan awkekstensi GNU , Anda juga bisa melakukan:

tmux -V | awk -v FPAT='[0-9]+' '{maj = $1; min = $2; print maj, min}'
Stéphane Chazelas
sumber
Terima kasih atas penjelasan tambahan tentang kompatibilitas!
villapx
13

Karena Anda menggunakan GNU awk, Anda dapat menggunakan bentuk 3-arg match()untuk menyimpan beberapa grup pengambilan:

awk '
    match($0, /([0-9]+)\.([0-9]+)/, m) {maj=m[1]; min=m[2]; print maj, min}
' <<END
tmux 2.8
tmux 1.9a
tmux 2.10
END
2 8
1 9
2 10

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

glenn jackman
sumber
5

Anda dapat membagi versi menjadi array:

awk '{ split($2, ver, /[.a-z]/) }'

lalu gunakan ver[1]sebagai ganti maj, ver[2]alih-alih min.

Menambahkan a-zke pemisah menghapus huruf kecil apa pun dari nomor versi. (Solusi lain lebih baik di sini karena mereka secara eksplisit mengekstraksi angka.)

Stephen Kitt
sumber
3

Pengguna lain memposting jawaban ini, dan kemudian dihapus. Saya pikir itu berguna:

Dengan menggunakan split()fungsi ini, pisahkan string versi ke dalam array ver, lalu akses ver[1]dan ver[2]alih - alih majdan minmasing-masing (atau cukup simpan nilai dalam variabel tersebut):

tmux -V | awk '{ split($2, ver, /[.a-z]/); print ver[1], ver[2] }'

Nilai tambah di sini adalah bahwa split()itu bukan gawkekstensi (meskipun argumen opsional keempatnya sepsadalah).

villapx
sumber
+1 tetapi mengapa digunakan /[.a-z]/sebagai argumen (pemisahan bidang) ketiga dari splitfungsi string, bukan hanya "."?
Cbhihe
2
@Cbhihe melihat penjelasan pada jawaban saya (yang saya hapus karena villapx menganggap itu berguna, terima kasih villapx!).
Stephen Kitt