好的,所以我喜欢我的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
在$1
and上使用命令$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