Menggunakan fungsi bash shell di dalam AWK


24

Apakah mungkin menggunakan fungsi bash di dalam AWK?

Contoh file (string, int, int, int)

Mike 247808 247809 247810

Mencoba mengonversi nilai dari desimal ke heksadesimal.

Fungsi didefinisikan baik dalam .bashrc atau dalam skrip shell.

awk '{print $1 ; d2h($2)}' file

awk: memanggil fungsi yang tidak ditentukan input data d2h nomor 1, file sumber nomor baris 1

Jawaban:


27

Coba gunakan system()fungsi:

awk '{printf("%s ",$1); system("d2h " $2)}' file

Dalam kasus Anda systemakan memanggil d2h 247808dan kemudian menambahkan output dari perintah ini ke printfkeluaran:

Mike 3C800

EDIT:

Sebagai systemkegunaan shalih-alih, bashsaya tidak dapat menemukan cara untuk mengakses .bashrc. Tetapi Anda masih dapat menggunakan fungsi dari skrip bash Anda saat ini:

#!/bin/bash
d2h() {
    # do some cool conversion here
    echo "$1" # or just output the first parameter
}
export -f d2h
awk '{printf("%s ",$1); system("bash -c '\''d2h "$2"'\''")}' file

EDIT 2:

Saya tidak tahu mengapa, tetapi ini tidak berfungsi pada Ubuntu 16.04 saya. Ini aneh, karena dulu berfungsi di Ubuntu 14.04.


Ini bisa berfungsi jika d2hdapat dieksekusi, tetapi tidak jika itu merupakan "fungsi yang didefinisikan baik dalam .bashrc atau dalam skrip shell".
Michael Homer

@MichaelHomer ya, Anda benar. Berkat komentar Anda, saya menyadari saya telah menjawab pertanyaan yang tidak ada yang ditanyakan. Tapi saya telah menemukan cara untuk menggunakan fungsi dari skrip saat ini (dan mungkin dari skrip lain melalui source) tetapi saya tidak bisa mencari tahu mengapa itu tidak berfungsi .bashrc.
akarilimano

2
Itu juga kerentanan perintah injeksi karena konten $2akhirnya ditafsirkan sebagai kode shell.
Stéphane Chazelas

8

Anda dapat memanggil bash dari awk dan menggunakan hasilnya. Itu jelas berbahaya dari perspektif kinerja jika terlalu sering terjadi. Mengutip halaman manual:

command | getline [var]

Jalankan perintah perpipaan output ke $ 0 atau var,

perintah akan menjadi skrip bash yang berisi definisi fungsi dan menjalankan fungsi.


Hauke ​​Laging, sangat keren!
JJoao

Saya telah menggunakan ini berkali-kali, dan itu bekerja dengan baik.
Dave Rix

4

Coba lakukan ini:

awk '{print $1 ; printf "%x\n", $2}' file

AFAIK, Anda tidak bisa menggunakan fungsi bash di awk tetapi hanya skrip. Anda dapat menggunakan fungsi awk jika perlu.


3

Menggunakan fungsi bash yang ditentukan pengguna di dalam awk

Penafian: Saya menyadari ini bukan apa yang OP coba lakukan, tetapi Google akan mengarahkan orang lain seperti saya ke jawaban ini.

Situasi

Anda memiliki bashskrip yang disusun dengan fungsi-fungsi (karena Anda tidak membenci diri sendiri atau [kebanyakan] rekan kerja) dan setidaknya 1 dari fungsi-fungsi tersebut perlu memanggil yang lain dari dalam awk.

Larutan

Naskah

#!/bin/env bash

# The main function - it's a sound pattern even in BASH
main(){
    # In the awk command I do some tricky things with single quotes. Count carefully...
    # The first $0 is outside the single quotes so it is the name of the current bash script.
    # The second $0 is inside the single quotes so it is awk's current line of input.
    awk '{printf("%s. ", ++c); system("'$0' --do"); print $0}'<<-PRETEND_THIS_IS_AN_INPUT_STREAM
        and
        and
        well
    PRETEND_THIS_IS_AN_INPUT_STREAM
}

# functionized to keep things DRY
doit(){
    echo -n "doin' it "
}


# check for a command switch and call different functionality if it is found
if [[ $# -eq 1 && $1 == "--do" ]];
then
        doit
else
        main
fi

Keluaran

$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well

Saya mewakili Queens, dia dibesarkan di Brooklyn
Bruno Bronosky

3

awkdapat menjalankan awkfungsi. Agar dapat menjalankan bashfungsi, Anda perlu awkmengeksekusi bashshell, bashuntuk menginterpretasikan definisi fungsi itu, dan memanggil fungsi itu, dengan nilai yang diekstraksi dengan awkditeruskan sebagai argumen.

Tidak sepele.

bashmendukung fungsi ekspor sehingga tersedia dalam pemanggilan berikutnya bash, jadi itu salah satu cara untuk meneruskan definisi fungsi ke pemanggilan basholeh awk:

export -f d2h

Satu-satunya cara untuk awkmenjalankan perintah (di bashsini) adalah dengan system("cmd"), atau print... | "cmd"atau "cmd" | getline. Dalam semua kasus, awkjalankan shell untuk menafsirkannya cmd, tetapi itu akan menjadi sh, bukan bash. Jadi, Anda perlu membuat baris perintah untuk shitu adalah bashdoa yang menginterpretasikan bashbaris perintah untuk memanggil fungsi, jadi Anda harus berhati-hati dengan mengutip:

export -f d2h
<file awk -v q="'" '
  function shquote(s) {
    gsub(q, q "\\" q q, s)
    return q s q
  }
  {print $1; system("bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'

Itu berarti menjalankan satu shdan satu bashuntuk setiap baris, sehingga akan menjadi sangat tidak efisien. Itu akan menjadi jauh lebih tidak efisien daripada bashmembaca dan membelah dengan while read loop:

(unset IFS; while read -r a b rest; do
  printf '%s\n' "$a"
  d2h "$b"
 done < file)

0

Ini akan memberi Anda peluang bagus.

cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk '{system("date"); print $1}'

fungsi sistem memungkinkan Anda untuk mem-parsing perintah bash dalam aliran awk.


0

Hanya peretasan singkat yang menunjukkan @HaukeLaging command|getline :

1) biarkan input menjadi:

Dear friends
my name is `id -nu` and
today is `date "+%Y-%m-%d"`.

Mengikuti sintaksis shell, pada input,

`command`

digunakan untuk menunjukkan perintah inline yang akan diganti oleh hasil eksekusi.

2) Kami dapat memperluas perintah shell inline dengan:

#!/usr/bin/gawk -f

BEGIN  { FS ="`";        }
NF==3  { $2 | getline $2 }
       { print           }

3) Penggunaan (setelah chmod biasa):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.