Использование функции оболочки bash внутри AWK

24

Можно ли как-то использовать функцию bash внутри AWK?

Файл примера (строка, int, int, int)

Mike 247808 247809 247810

Попытка преобразовать значения из десятичного в шестнадцатеричное.

Функция определена либо в .bashrc, либо в сценарии оболочки.

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

awk: вызов неопределенной функции d2h входная запись номер 1, строка файла исходного файла номер 1

крошечный
источник

Ответы:

27

Попробуйте использовать system()функцию:

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

В вашем случае systemвызовет d2h 247808и затем добавит вывод этой команды к printfвыводу:

Mike 3C800

РЕДАКТИРОВАТЬ:

Как systemиспользует shвместо bashя не могу найти способ доступа .bashrc. Но вы все равно можете использовать функции из вашего текущего скрипта 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

РЕДАКТИРОВАТЬ 2:

Я не знаю почему, но это не работает на моем Ubuntu 16.04. Это странно, потому что раньше он работал на Ubuntu 14.04.

akarilimano
источник
Это могло бы работать, если бы d2hбыл исполняемый файл, но не в том случае, если это «функция, определенная либо в .bashrc, либо в сценарии оболочки».
Майкл Гомер
@MichaelHomer да, ты прав. Благодаря вашему комментарию я понял, что ответил на вопрос, который никто не задавал. Но я нашел способ использовать функции из текущего скрипта (и, возможно, из других скриптов через source), но я не могу понять, почему он не работает .bashrc.
akarilimano
2
Это также уязвимость, связанная с внедрением команд, поскольку содержимое в $2конечном итоге интерпретируется как шелл-код.
Стефан Шазелас
8

Вы можете вызвать bash из awk и использовать его вывод. Это очевидно опасно с точки зрения производительности, если это происходит слишком часто. Цитирую справочную страницу:

command | getline [var]

Запустите команду, передающую выходные данные либо в $ 0, либо в переменную,

Команда будет скриптом bash, который содержит определение функции и выполняет функцию.

Хауке Лагинг
источник
Хауке Лагинг, очень круто!
JJoao
Я использовал это много раз, и это работает хорошо.
Дэйв Рикс
4

Попробуйте сделать это:

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

AFAIK, вы не можете использовать функцию bash в awk, а только скрипт. При необходимости вы можете использовать функцию awk.

Жиль Квено
источник
3

Использование определенной пользователем функции bash внутри awk

Отказ от ответственности: я понимаю, что это не то, что ОП пытается сделать, но Google приведет других, как я, к этому ответу.

ситуация

У вас есть bashсценарий, организованный с помощью функций (потому что вы не ненавидите себя или [большинство] коллег), и по крайней мере одна из этих функций должна вызывать другую изнутри awk.

Решение

скрипт

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

Выход

$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well
Бруно Броноски
источник
Я представляю королев, она была воспитана в Бруклине
Бруно Броноски
3

awkможет запускать awkфункции. Чтобы запустить bashфункции, вам необходимо awkвыполнить bashоболочку, которая bashинтерпретирует определение этой функции, и вызовите эту функцию со значением, извлеченным с помощью awkаргумента.

Не тривиально.

bashподдерживает экспорт функций, поэтому он доступен в последующих вызовах bash, так что это один из способов передать определение функции bashвызываемой функции awk:

export -f d2h

Единственные способы awkвыполнить команду ( bashздесь) - это ее system("cmd")или, print... | "cmd"или "cmd" | getline. Во всех случаях awkзапускается оболочка для интерпретации этого cmd, но это shне так bash. Таким образом, вам нужно создать командную строку для shэтого bashвызова, который интерпретирует bashкомандную строку для вызова функции, поэтому вы должны быть осторожны с цитированием:

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

Это означает, что нужно запускать один shи один bashдля каждой строки, так что это будет довольно неэффективно. В конечном итоге это будет даже значительно более неэффективно, чем bashчтение и разбиение с помощью while read loop:

(unset IFS; while read -r a b rest; do
  printf '%s\n' "$a"
  d2h "$b"
 done < file)
Стефан Шазелас
источник
0

Это даст вам хорошие шансы.

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

Системная функция позволяет вам анализировать команду bash в потоке awk.

Мансур Али
источник
0

Просто быстрый взлом демонстрации @HaukeLaging command|getline :

1) пусть вход будет:

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

Следующий синтаксис оболочки, на входе,

`command`

используется для обозначения встроенных команд, которые должны быть заменены результатом его выполнения.

2) Мы можем расширить встроенную команду оболочки:

#!/usr/bin/gawk -f

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

3) Использование (после обычного chmod):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
JJoao
источник