1

我正在尝试编写一个 Bash 脚本,该脚本读取包含多列数据的文件,并将第二列中的每个值乘以第三列中的每个值,将所有这些乘法的结果加在一起。

例如,如果文件看起来像这样:

Column 1    Column 2    Column 3    Column 4
genome      1           30          500
genome      2           27          500
genome      3           83          500
...

脚本应该乘以 1*30 得到 30,然后 2*27 得到 54(并将其加到 30),然后 3*83 得到 249(并将其加到 84)等等。

我一直在尝试使用 awk 来解析输入文件,但不确定如何让操作逐行进行。现在它在读取第一行并执行变量操作后停止。

这是我到目前为止所写的:

for file in fileone filetwo
do
    set -- $(awk '/genome/ {print $2,$3}' $file.hist)
    var1=$1
    var2=$2
    var3=$((var1*var2))
    total=$((total+var3))

    echo var1 \= $var1
    echo var2 \= $var2
    echo var3 \= $var3
    echo total \= $total
done

我尝试在所有内容周围放置一个“while read”循环,但无法让变量随每一行更新。我想我会以错误的方式解决这个问题!

我对 Linux 和 Bash 脚本非常陌生,因此将不胜感激任何帮助!

4

2 回答 2

2

那是因为 awk 读取整个文件并在每一行上运行它的程序。所以你得到的输出awk '/genome/ {print $2,$3}' $file.hist看起来像

1 30
2 27
3 83

依此类推,这意味着在 bash 脚本中,该set命令进行以下变量赋值:

$1 = 1
$2 = 30
$3 = 2
$4 = 27
$5 = 3
$6 = 83

等等但是你只在你的脚本中使用$1$2,这意味着文件的其余内容——第一行之后的所有内容——都被丢弃了。

老实说,除非您这样做只是为了学习如何使用 bash,否则我会说只是在 awk 中进行。由于 awk 会自动遍历文件中的每一行,因此很容易将第 2 列和第 3 列相乘并保持运行总计。

awk '{ total += $2 * $3 } ENDFILE { print total; total = 0 }' fileone filetwo

ENDFILE是一个特殊的地址,意思是“在每个文件的末尾运行下一个块,而不是在每一行。”

如果您这样做是出于教育目的,让我这样说:关于在 bash 中进行算术运算,您唯一需要知道的是,您永远不应该在 bash 中进行算术运算:-P 说真的,当您想要操作数字时,bash 是最适合这项工作的工具之一。但是,如果您真的想知道,我可以对其进行编辑以包含一些有关如何主要在 bash 中执行此任务的信息。

于 2013-03-15T21:22:36.390 回答
0

我同意这awk通常更适合这种工作,但如果您好奇纯bash实现会是什么样子:

for f in file1 file2; do
    total=0
    while read -r _ x y _; do
        ((total += x * y))
    done < "$f"
    echo "$total"
done
于 2013-03-15T21:36:35.877 回答