2015-03-23 2 views
0

Я пытаюсь использовать bc в awk-скрипте. В приведенном ниже коде я пытаюсь преобразовать шестнадцатеричное число в двоичный код и сохранить его в переменной.Использование bc in awk

#!/bin/awk -f 

{ 
    binary_vector = $(bc <<< "ibase=16;obase=2;FF") 
} 

Куда я иду не так?

+3

Вы пытаетесь использовать awk, как вы бы использовали bash. Это два разных языка, предназначенные для двух разных вещей, поэтому вы не можете брать синтаксис из одного и использовать его в другом. Пожалуйста, отредактируйте свой вопрос, чтобы показать нам, что именно вы пытаетесь сделать. Некоторый вход и желаемый выход всегда полезны. –

+0

То, что вы поставили в сообщение до сих пор, не использует ничего, что делает 'awk'. Почему 'awk' участвует здесь вообще? –

+0

Я хочу узнать из принятого ответа этого сообщения [ссылка] (http://stackoverflow.com/questions/18870209/convert-a-decimal-number-to-hexadecimal-and-binary-in-a-shell- сценарий). В моем случае я хочу сохранить значение в переменной. –

ответ

2

Не сказать, что это хорошая идея, но:

$ awk 'BEGIN { 
    cmd = "bc <<< \"ibase=16;obase=2;FF\"" 
    rslt = ((cmd | getline line) > 0 ? line : -1) 
    close(cmd) 
    print rslt 
}' 
11111111 

Также см http://gnu.org/software/gawk/manual/gawk.html#Bitwise-Functions и http://gnu.org/software/gawk/manual/gawk.html#Nondecimal-Data

+1

Твердый, но поскольку команда оболочки передается 'sh', где' <<< 'может не работать, лучше использовать' cmd = 'printf \ "ibase = 16; obase = 2; FF \ n \" | Ьс "'. (Я знаю, что вы просто повторно использовали команду оболочки OP, но я думаю, что это изменение все равно стоит сделать.) – mklement0

+0

Я просто показываю OP правильный способ указать пистолет на ногу после того, как он загрузил пули :-). Не стесняйтесь редактировать мой ответ, чтобы добавить синтаксис printf, если хотите. –

+2

:) Достаточно справедливо. Я позволю этим комментариям рассказать историю. – mklement0

1

Следующая один лайнер Awk скрипт должен делать то, что вы хотите:

awk -vVAR=$(read -p "Enter number: " -u 0 num; echo $num) \ 
'BEGIN{system("echo \"ibase=16;obase=2;"VAR"\"|bc");}' 

Объяснение:

-vVAR Передает переменную VAR в Awk

Устанавливает переменную VAR из оболочки на вход пользователя.

system("echo ... |bc") Использует встроенную команду Awk для выполнения команд оболочки. Обратите внимание на то, как цитирование останавливается в переменной VAR, а затем продолжается сразу после него, то есть Awk интерпретирует VAR как переменную Awk, а не как часть строки, помещенной в системный вызов.

Update - использовать его в переменной Awk:

awk -vVAR=$(read -p "Enter number: " -u 0 num; echo $num) \ 
'BEGIN{s="echo \"ibase=16;obase=2;"VAR"\"|bc"; s | getline awk_var;\ 
close(s); print awk_var}' 

s | getline awk_var поместит вывод команды s в переменную Awk awk_var. Обратите внимание, что строка построена до отправки ее в getline - если нет (если вы не скопируете конкатенацию строк) Awk попытается отправить ее в getline в отдельные части% s VAR% s.

close(s) закрывает трубу - хотя для bc это не имеет значения и Awk автоматически закрывает трубы на выходе - если поставить это в более сложный сценарий Awk, лучше явно закрывать трубу. Согласно документации Awk некоторые команды, такие как mail, будут ждать, пока труба закрывается до завершения.

http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_39.html

+0

Необычное требование - считывать вывод команды 'bc' в переменную _awk_ из _inside_ awk-программы. Без этого вы можете просто вызвать 'bc' внутри вашей подстановки команд и (также) передать результат в' awk'. В стороне: вы добавили '-u 0' в свою команду' read', чтобы сделать его явным, что вы читаете из stdin, или есть еще одна причина? – mklement0

+0

Спасибо, я пошел прямо к семантике. Я обновил свой ответ - и да, я использую '-u 0' для чтения, чтобы быть явным, потому что у меня возникли проблемы со сложными сценариями оболочки, которые работают с дескрипторами - это более безопасно, чтобы быть явным imo , –

+0

Хорошее обновление (справочная информация о 'close'), но я не думаю, что вы правы в том, что« если вы этого не сделаете, Awk попытается отправить его на getline в штуках (% s VAR% s) »- Строковый литерал должен работать нормально (предполагая, что вы не планируете называть 'close'). Также обратите внимание, что для некоторых реализаций Awk (например, BSD Awk) требуется пространство между '-v' и' VAR = ... '. – mklement0

0

Кстати вы написали свой пример, это выглядит, как вы хотите, чтобы преобразовать запись AWK (строки) в ассоциативный массив. Вот AWK исполняемый скрипт, который позволяет, что, выполнив команду bc над значениями в split типа массива: с

#!/usr/bin/awk -f 

{ 
    # initialize the a array 
    cnt = split($0, a, FS) 

    if(convertArrayBase(10, 2, a, cnt) > -1) { 

     # use the array here 
     for(i=1; i<=cnt; i++) { 
      print a[i] 
     } 
    } 
} 

    # Destructively updates input array, converting numbers from ibase to obase 
    # 
    # @ibase: ibase value for bc 
    # @obase: obase value for bc 
    # @a:  a split() type associative array where keys are numeric 
    # @cnt: size of a (number of fields) 
    # 
    # @return: -1 if there's a getline error, else cnt 
    # 
function convertArrayBase(ibase, obase, a, cnt,   i, b, cmd) { 

    cmd = sprintf("echo \"ibase=%d;obase=%d", ibase, obase) 
    for(i=1; i<=cnt; i++) { 
     cmd = cmd ";" a[i] 
    } 
    cmd = cmd "\" | bc" 

    i = 0 # reset i 
    while((cmd | getline b) > 0) { 
     a[++i] = b 
    } 
    close(cmd) 
    return i==cnt ? cnt : -1 
} 

При использовании с входом:

1 2 3 
4 s 1234567 

Этот сценарий выводит следующее:

1 
10 
11 
100 
0 
100101101011010000111 

Функция convertArrayBase работает на split типах массивов. Таким образом, вы должны инициализировать входной массив (a здесь) с полной строкой (как показано) или подфайлами поля (не показаны) перед вызовом. Он разрушает массив.

Вы можете вместо этого позвонить bc непосредственно с некоторыми вспомогательными файлами, чтобы получить аналогичный вывод. Я не обнаружил, что bc поддерживается - (stdin как файл), так что это немного больше, чем хотелось бы.

Изготовление start_cmds файла, как это:

ibase=10;obase=2; 

и quit_cmd как:

;quit 

Учитывая входной файл (называемый data.semi), где данные, разделенные ;, как это:

1;2;3 
4;s;1234567 

Вы можете r ип bc как:

$ bc -q start_cmds data.semi quit_cmd 
1 
10 
11 
100 
0 
100101101011010000111 

, который те же данные, что сценарий AWK выводит, но только вызов bc один раз со всеми входами. Теперь, в то время как эти данные не в массиве AWK ассоциативного в скрипте bc выход может быть записан в виде стандартного ввода входных данных для AWK и reassembed в массив, как:

bc -q start_cmds data.semi quit_cmd | awk 'FNR==NR {a[FNR]=$1; next} END { for(k in a) print k, a[k] }' - 
1 1 
2 10 
3 11 
4 100 
5 0 
6 100101101011010000111 

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