在awk中使用bc

时间:2015-03-23 17:14:32

标签: bash awk bc

我正在尝试在awk脚本中使用bc。在下面的代码中,我试图将十六进制数转换为二进制并将其存储在变量中。

#!/bin/awk -f

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

我哪里出错了?

3 个答案:

答案 0 :(得分: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-Functionshttp://gnu.org/software/gawk/manual/gawk.html#Nondecimal-Data

答案 1 :(得分: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

-vVAR=$(read -p ... )设置变量VAR  shell给用户输入。

system("echo ... |bc")使用内置的awk系统命令来执行shell命令。注意引用如何在变量VAR处停止,然后在它之后继续,这就是说awk将VAR解释为Awk变量而不是作为放入系统调用的字符串的一部分。

更新 - 在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

答案 2 :(得分: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

你可以像bc那样运行:

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

与awk脚本输出的数据相同,但只使用所有输入一次调用bc。现在,虽然该数据不在脚本中的awk关联数组中,但bc输出可以写为awdin的stdin输入并重新组合成一个数组,如:

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视为输入文件,并允许您稍后添加其他文件进行处理。