Using bc in awk

与世无争的帅哥 提交于 2019-12-12 04:56:54

问题


I am trying to use bc in an awk script. In the code below, I am trying to convert hexadecimal number to binary and store it in a variable.

#!/bin/awk -f

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

Where do I go wrong?


回答1:


Not saying it's a good idea but:

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

Also see http://gnu.org/software/gawk/manual/gawk.html#Bitwise-Functions and http://gnu.org/software/gawk/manual/gawk.html#Nondecimal-Data




回答2:


The following one-liner Awk script should do what you want:

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

Explanation:

-vVAR Passes the variable VAR into Awk

-vVAR=$(read -p ... ) Sets the variable VAR from the shell to the user input.

system("echo ... |bc") Uses the Awk system built in command to execute the shell commands. Notice how the quoting stops at the variable VAR and then continues just after it, thats so that Awk interprets VAR as an Awk variable and not as part of the string put into the system call.

Update - to use it in an Awk variable:

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 will put the output of the command s into the Awk variable awk_var. Note the string is built before sending it to getline - if not (unless you parenthesize the string concatenation) Awk will try to send it to getline in separate pieces %s VAR %s.

The close(s) closes the pipe - although for bc it doesn't matter and Awk automatically closes pipes upon exit - if you put this into a more elaborate Awk script it is best to explicitly close the pipe. According to the Awk documentation some commands such as mail will wait on the pipe to close prior to completion.

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




回答3:


By the way you wrote your example, it looks like you want to convert an awk record ( line ) into an associative array. Here's an awk executable script that allows that by running the bc command over values in a split type array:

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

When used with an input of:

1 2 3
4 s 1234567

this script outputs the following:

1
10
11
100
0
100101101011010000111

The convertArrayBase function operates on split type arrays. So you have to initialize the input array (a here) with the full row (as shown) or a field's subflds(not shown) before calling the it. It destructively updates the array.

You could instead call bc directly with some helper files to get similar output. I didn't find that bc supported - ( stdin as a file name ) so it's a little more than I'd like.

Making a start_cmds file like this:

ibase=10;obase=2;

and a quit_cmd like:

;quit

Given an input file (called data.semi) where the data is separated by a ;, like this:

1;2;3
4;s;1234567

you can run bc like:

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

which is the same data that the awk script is outputting, but only calling bc a single time with all of the inputs. Now, while that data isn't in an awk associative array in a script, the bc output could be written as stdin input to awk and reassembed into an array like:

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

where the final dash is telling awk to treat stdin as an input file and lets you add other files later for processing.



来源:https://stackoverflow.com/questions/29216278/using-bc-in-awk

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!