Usando a função bash shell dentro do AWK


24

É possível usar a função bash no AWK de alguma forma?

Arquivo de exemplo (string, int, int, int)

Mike 247808 247809 247810

Tentando converter valores de decimal em hexadecimal.

Função definida no .bashrc ou no shell script.

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

awk: chamando a função indefinida d2h número de registro de entrada 1, número da linha de origem 1 do arquivo de arquivo

Respostas:


27

Tente usar a system()função:

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

No seu caso system, chamará d2h 247808e depois anexará a saída deste comando à printfsaída:

Mike 3C800

EDITAR:

Como systemusos em shvez de bashnão consigo encontrar uma maneira de acessar .bashrc. Mas você ainda pode usar funções do seu script atual do bash:

#!/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:

Não sei por que, mas isso não está funcionando no meu Ubuntu 16.04. Isso é estranho, porque costumava funcionar no Ubuntu 14.04.


Isso poderia funcionar se d2hfosse um executável, mas não se for uma "função definida no .bashrc ou no shell script".
Michael Homer

@MichaelHomer sim, você está certo. Graças ao seu comentário, percebi que respondi à pergunta que ninguém fez. Mas eu encontrei uma maneira de usar funções do script atual (e possivelmente de outros scripts via source), mas não consigo descobrir por que ele não funciona .bashrc.
akarilimano 22/09

2
Essa também é uma vulnerabilidade de injeção de comando, pois o conteúdo de $2acaba sendo interpretado como código shell.
Stéphane Chazelas

8

Você pode chamar o bash do awk e usar sua saída. Isso é obviamente perigoso do ponto de vista do desempenho, se acontecer com muita frequência. Citando a página de manual:

command | getline [var]

Execute o comando canalizando a saída para $ 0 ou var,

O comando seria um script bash que contém a definição da função e executa a função.


Hauke ​​Laging, muito legal!
precisa saber é

Eu usei isso muitas vezes e funciona bem.
Dave Rix

4

Tente fazer isso:

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

AFAIK, você não pode usar uma função bash no awk, mas apenas um script. Você pode usar uma função awk, se necessário.


3

Usando uma função bash definida pelo usuário dentro do awk

Isenção de responsabilidade: sei que não é isso que o OP está tentando fazer, mas o Google levará outras pessoas como eu a essa resposta.

Situação

Você tem um bashscript organizado com funções (porque você não se odeia nem com a [maioria] dos colegas de trabalho) e pelo menos uma dessas funções precisa chamar outra de dentro awk.

Solução

Roteiro

#!/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

Saída

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

Eu represento o Queens, ela foi criada no Brooklyn
Bruno Bronosky

3

awkpode executar awkfunções. Para executar bashfunções, você precisa awkexecutar um bashshell que bashinterprete a definição dessa função e chame essa função, com o valor extraído por awkpassado como argumentos.

Não é trivial.

bashsuporta funções de exportação, para que esteja disponível em chamadas subsequentes de bash, portanto, é uma maneira de passar a definição da função para a bashchamada por awk:

export -f d2h

As únicas maneiras de awkexecutar um comando ( bashaqui) são com system("cmd"), ou print... | "cmd"ou "cmd" | getline. Em todos os casos, awkexecuta um shell para interpretar isso cmd, mas será sh, não bash. Portanto, você precisa construir uma linha de comando, pois shessa é uma bashchamada que interpreta uma bashlinha de comando para chamar a função; portanto, você deve ter cuidado ao citar:

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))}'

Isso significa executar um she um bashpara cada linha, por isso será bastante ineficiente. Isso acabaria sendo ainda mais ineficiente do que bashfazer a leitura e a divisão com um while read loop:

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

0

Isso lhe dará boas chances.

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

A função do sistema permite analisar o comando bash no fluxo do awk.


0

Apenas um hack rápido demonstra @HaukeLaging command|getline :

1) deixe a entrada ser:

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

Após a sintaxe do shell, na entrada,

`command`

é usado para indicar comandos em linha a serem substituídos pelo resultado de sua execução.

2) Nós podemos expandir o comando shell embutido:

#!/usr/bin/gawk -f

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

3) Uso (após o chmod usual):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.