
Можно ли как-то использовать функцию bash внутри AWK?
Пример файла (строка, целое, целое, целое)
Mike 247808 247809 247810
Попытка преобразовать значения из десятичных в шестнадцатеричные.
Функция определена либо в .bashrc
скрипте оболочки, либо в нем.
$ awk '{print $1 ; d2h($2)}' file
awk: calling undefined function d2h
input record number 1, file file
source line number 1
решение1
Попробуйте использовать system()
функцию:
awk '{printf("%s ",$1); system("d2h " $2)}' file
В вашем случае system
вызовем d2h 247808
и затем добавим вывод этой команды к printf
выводу:
Mike 3C800
РЕДАКТИРОВАТЬ:
As 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
Примечание: -f
используется дляэкспортировать функциюа не переменная.
ПРАВКА 2:
Не знаю почему, но это не работает на моем Ubuntu 16.04. Это странно, потому что раньше это работало на Ubuntu 14.04.
решение2
Вы можете вызвать bash из awk и использовать его вывод. Это, очевидно, опасно с точки зрения производительности, если это происходит слишком часто. Цитата из man-страницы:
command | getline [var]
Выполнить команду, перенаправив вывод в $0 или var,
команда будет представлять собой bash-скрипт, содержащий определение функции и выполняющий эту функцию.
решение3
Перевод из десятичной системы в шестнадцатеричную — это то, что awk
может сделать само. И вы можете определитьawk
Функция, которая это делает:
function d2h(d) {
return sprintf("%x", d)
}
Теперь, чтобы ответить на вопрос в общем случае, для 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("exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'
Если вы хотите вернуть вывод функции обратно в awk
, вам нужно будет передать его обратно через канал. Для этого вы должны использовать cmd | getline
вместо system(cmd)
(что оставляет cmd
stdout нетронутым).
cmd | getline line
магазиныодна линия(строго говоряодна запись, записи по умолчанию являются строками), поэтому для получения всего вывода в случаях, когда он состоит из нескольких строк, вам понадобится такой цикл:
awk '...
cmd = "exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2)
output = ""
while ((cmd | getline line) > 0) {
output = output line RS
}
sub(RS "$", "", output) # remove the last newline
...'
Это означает запуск одного sh
и одного bash
для каждого вызова функции, поэтому это будет довольно неэффективно. Это в конечном итоге будет даже значительно более неэффективно, чем делать bash
чтение и разделение с помощью while read loop
:
(unset -v IFS; while read -r a b rest; do
printf '%s\n' "$a"
d2h "$b"
done < file)
Также обратите внимание, что начиная с shellshock, bash
теперь экспортируются функции в переменные окружения, которые называются как BASH_FUNC_d2h%%
. Некоторые sh
реализации, включая mksh
и более новые версииdash
удалятьэти переменные среды из среды:
$ env 'foo%%=bar' dash -c 'printenv foo%%'
$ env 'foo%%=bar' mksh -c 'printenv foo%%'
$ env 'foo%%=bar' zsh -c 'printenv foo%%'
bar
$ env 'foo%%=bar' bash -c 'printenv foo%%'
bar
Поэтому вместо того, чтобы полагаться на шаткую функцию экспорта функций, вы можете передать определение функции другим способом. Это может быть сделано через переменную окружения с обычным именем:
BASH_FUNCTIONS=$(typeset -f d2h) awk '
...
cmd = "exec bash -c '\''eval \"$BASH_FUNCTIONS\";" \
"d2h \"$1\"'\'' bash " shquote($2)
...'
решение4
Использование пользовательской функции 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