在这种情况下,如何从 awk 中调用 bc ?

在这种情况下,如何从 awk 中调用 bc ?

好的,所以我喜欢我的awk,但是,是的,它有精度问题,不幸的是,我没有简单的方法来安装称为 的多精度扩展gawkextlib

我正在做的是,我正在解决以下问题罗莎琳德信息使用外壳单衬。我发现在网站设定的五分钟时间内使用这些 shell 语句对 DNA/RNA 链执行所需的计算并不困难。

无论如何,我一直被这个问题困扰,但我总是想提高我对 Linux 工具的知识。在这种情况下,我需要bc从调用awk

命令bc应该是:

bc <<< "scale=1000; $1/$2"

其中$1$2是我正在使用的两列文本awk

awk命令源自我编写的一些 shell 函数:

nucleic-line () {
sed 's/\(.\)/\1\n/g' < $@
}

gc-numeric-count () {
n=$(nucleic-line $@ | wc -l)
m=$(nucleic-line $@ | grep -v "[AT]" | wc -l)
echo $m $n
}
export -f gc-numeric-count

column-percent-count () {
for f in $@; do gc-numeric-count $f; done | awk '{a = $1/$2 | print a * 100}'
}

就我的目的而言,awk '{a = $1/$2 | print a * 100}'还不够精确。它得到了正确的鸟嘌呤和胞嘧啶的百分比,但我需要它的小数位数超出了awk所能提供的范围。正如我所说,不幸的是我无法安装gawkextlib.我需要任意精度,所以我需要使用bc.但我也希望能够处理列,就像我可以在awk.

那么,如何修改最后一个表达式的最后一行以bc$1and上使用命令$2

答案1

你的问题是你把 shell 当作它不是的东西:一种编程语言。 shell 首先是一个命令行解释器。 shell脚本就是脚本。如果你用 shell 语法来实现你的问题的逻辑和算法,那么你就走错了路。

您的代码中存在明显的问题,例如未加引号的变量。但总而言之,运行这么多命令(因为 shell 是运行命令的工具,而不是编程语言)只是为了查找文件中除 A 和 T 之外的字符的比例,感觉很丑陋。

另外,awk 在内部使用 64 位浮点数。您确定您需要比这更高的精度吗?如果这些数字要被比这个更精确的东西使用,你不能使用它吗某物做整件事?

要回答你的问题,你会这样做:

$ echo 1 3 | awk -vRS= '{("echo scale=300\\;" $1 "/" $2 "|bc -l") | getline; print}'
.3333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333

但你可以很容易地看出这是多么毫无意义:awk 为每行输入运行一个 shell 和两个命令,读取它们的输出并再次打印......即使是外壳也可以做得很好,而不需要那么大惊小怪。

如果您仍然想使用 awk,一个稍微不那么愚蠢的方法是:

echo 1 3 | awk 'BEGIN{print "scale=300"}{print $1"/"$2}' | bc

到时候,只有一一awk命令bc

对我来说,很明显你需要一种真正的编程语言(我想到的是 perl、ruby、python)。您可以从 shell 脚本调用该编程语言的解释器,但只能调用一次:只需一次调用就足以完成整个任务。

答案2

不知道你的脚本的其余部分(我不知道你是否依赖于返回值$m $n其他地方)-你考虑过这个吗?

gc-numeric-count () {
  n=$(nucleic-line $@ | wc -l)
  m=$(nucleic-line $@ | grep -v "[AT]" | wc -l)
  echo "scale=1000;${m}/${n"}
}
export -f gc-numeric-count

column-percent-count () {
  for f in $@; do gc-numeric-count $f | bc -l; done 
}

答案3

我没有看到传递变量有任何问题。另外,GNU dc(包含在 bc 中)对于嵌入式计算、更少的管道和反向抛光来说要容易得多:

print '355 113' | awk -vRS='' '{"dc -e \"1000k"$1" "$2"/pq\"" | getline; print; close(dc)}

同意 Stephane 的观点,shell 做线索工作,awk 做格式化工作,计算应该进行 dc

相关内容