Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Function awk中用户定义函数的打印输出出现意外的令牌错误_Function_Variables_Awk_Printing - Fatal编程技术网

Function awk中用户定义函数的打印输出出现意外的令牌错误

Function awk中用户定义函数的打印输出出现意外的令牌错误,function,variables,awk,printing,Function,Variables,Awk,Printing,我想灵活地将两个小awk的输出打印到bash管道,这两个管道使用变量(它们最初工作)。我最初认为可以将整个命令本身存储为变量,但对于其中一个,它不起作用,显然()这不是一个好主意。所以我写了两个函数,但是我在“完成”附近得到了一个“意外标记”,但是它的格式与上面的链接一样 我的错在哪里 for coverage_file in */*.cov do #gene_count=$(awk '{print $5}' $coverage_file |sort | uniq -c | wc -l)

我想灵活地将两个小awk的输出打印到bash管道,这两个管道使用变量(它们最初工作)。我最初认为可以将整个命令本身存储为变量,但对于其中一个,它不起作用,显然()这不是一个好主意。所以我写了两个函数,但是我在“完成”附近得到了一个“意外标记”,但是它的格式与上面的链接一样

我的错在哪里

for coverage_file in */*.cov
do
    #gene_count=$(awk '{print $5}' $coverage_file |sort | uniq -c | wc -l) #this is apparently not a good idea
    #contig_count=$(awk '{print $1}' $coverage_file |sort | uniq -c | wc -l) #this is apparently not a good idea
    cmd_gene() { awk '{print $5}' $coverage_file |sort | uniq -c | wc -l }
    cmd_contig() { awk '{print $1}' $coverage_file |sort | uniq -c | wc -l }
    cmd_gene $coverage_file
    cmd_contig $coverage_file
    #print "we found", $gene_count, "genes on ",$contig_count" contigs
done
cov文件如下所示:

k141_85332.3 4119 19 A5 phnM_031
k141_85332.3 4119 19 A5 phnM_031
k141_85332.3 4119 28 A1 phnM_031
k141_85332.3 4119 28 A1 phnM_031
k141_85332.3 4119 8 A2 phnM_031
k141_85332.3 4119 8 A2 phnM_031
k141_88684 267 5 B10 phnM_032
k141_88684 268 5 B10 phnM_032
k141_88684 269 5 B10 phnM_032
k141_88684 270 5 B10 phnM_032
k141_88684 271 5 B10 phnM_032
k141_88684 272 5 B10 phnM_032
编辑:这包括接受的答案+可能的打印方式:

#!/bin/bash

#define variables
gene="phnM"
threshold="5"

#define functions
cmd_gene() { awk '{print $5}' $1 |sort | uniq -c | wc -l ; } #semicolon is important here!
cmd_contig() { awk '{print $1}' $1 |sort | uniq -c | wc -l ; } #semicolon is important here!

#loop over files and print results (would be prettier with printf)
for coverage_file in */*.cov
do
    echo $gene" was found" $(cmd_gene "$coverage_file") "times on" $(cmd_contig "$coverage_file")" contigs with minimum coverage of" $threshold in $coverage_file
done
输出:

phnM was found 67 times on 65 contigs with minimum coverage of 5 in phnm/test.cov
phnM was found 3 times on 2 contigs with minimum coverage of 5 in test/test.cov

出现意外的令牌错误,因为定义函数时,}必须在自己的行上或前面加

此外,由于在函数定义中使用了
$coverage\u file
,因此不必传递它

for coverage_file in */*.cov
do
    cmd_gene() { awk '{print $5}' $coverage_file |sort | uniq -c | wc -l; }
    cmd_contig() { awk '{print $1}' $coverage_file |sort | uniq -c | wc -l; }
    cmd_gene 
    cmd_contig 
    #print "we found", $gene_count, "genes on ",$contig_count" contigs
done
如果要在for循环之外定义函数,可以使用
$1
(不要与awk的$1混淆)并像以前一样传递
$coverage\u文件

编辑:上述示例

$ cat a.sh
cmd_gene() { awk '{print $5}' $1 |sort | uniq -c | wc -l; }
cmd_contig() { awk '{print $1}' $1 |sort | uniq -c | wc -l; }

for coverage_file in */*.cov
do
    cmd_gene $coverage_file
    cmd_contig $coverage_file
done

$ ls */*.cov
bf/a.cov

$ cat */*.cov
k141_85332.3 4119 19 A5 phnM_031
k141_85332.3 4119 19 A5 phnM_031
k141_85332.3 4119 28 A1 phnM_031
k141_85332.3 4119 28 A1 phnM_031
k141_85332.3 4119 8 A2 phnM_031
k141_85332.3 4119 8 A2 phnM_031
k141_88684 267 5 B10 phnM_032
k141_88684 268 5 B10 phnM_032
k141_88684 269 5 B10 phnM_032
k141_88684 270 5 B10 phnM_032
k141_88684 271 5 B10 phnM_032
k141_88684 272 5 B10 phnM_032

$ sh a.sh
       2
       2

@jas回答了你的问题,所以请坚持下去,以下是一种更好的方法,可以用来做你想做的事情,因为它太大/格式不适合发表评论:

awk '
BEGIN {
    gene = "phnM"
    threshold = "5"
}
{
    genes[$5]
    contigs[$1]
}
ENDFILE {
    printf "%s was found %d times on %d contigs with minimum coverage of %d in %s\n",
        gene, length(genes), length(contigs), threshold, FILENAME
    delete genes
    delete contigs
}
' */*.cov
上面对ENDFILE使用GNU awk,但如果需要,使其适用于其他awk只是一个小改动:

awk '
BEGIN {
    gene = "phnM"
    threshold = "5"
}
FNR==1 { prt() }
{
    genes[$5]
    contigs[$1]
}
END { prt() }
function prt() {
    if (fname != "") {
        printf "%s was found %d times on %d contigs with minimum coverage of %d in %s\n",
            gene, length(genes), length(contigs), threshold, fname
        delete genes
        delete contigs
    }
    fname = FILENAME
}
' */*.cov

有关操作文本时避免shell循环的一些原因,请参见。

意外的标记错误即将出现,因为定义函数时,}必须位于自己的行上或前面有
。例如:
cmd_contig(){awk'{print$1}'$coverage_file | sort | uniq-c | wc-l;}
hm-ja这很尴尬;-)谢谢你想把它作为一个答案吗?甚至不想让人难堪;当然,我将添加一个答案,谢谢。考虑<代码> AWK {基因[$ 5 ];COTIGS[ $ 1 ] } {打印长度(基因)ORS长度(CONTIGS)}“$CurrAgEXFILE文件” -它将给出与两个函数相同的输出,而不需要多次调用外部命令、管道等,当然,您根本不需要外壳循环,您只需调用一个小而琐碎的awk脚本就可以完成整个过程。谢谢Ed,这非常令人印象深刻,但我不知道它是如何工作的?为什么要使用prt()函数两次,一次只在第一个文件的第一条记录中使用?在GNU awk中,当我们到达每个输入文件的末尾时,ENDFILE构造是真的。因此,如果我们想在处理每个文件后打印一些信息,我们只需将其放在ENDFILE块中。在其他AWK中,我们没有这一点,所以我们需要模拟它。FNR==1是一个条件,当读取每个文件的第一行时,该条件为真,因此我可以在FNR==1块中打印当前文件的前一个文件的信息。这使得我们在读取最终输入文件时仍然需要做一些事情,因此我们在FNR==1部分中所做的事情必须在结束部分中复制,通常是通过从FNR==1和结束块调用的公共函数(
prt()
)来完成。啊,我明白了,所以如果
*/*.cov
部分将找到20个输入文件,前19个文件的结果将由
FNR==1{prt()}
打印,第20个结果来自
END{prt()}
,对吗?非常感谢您的解释,请注意,有一个边缘情况,使用EntFrand和非GAWK FNR==1/Engult解决方案不会产生相同的输出,也就是说,如果您可以在列表中间有空的输入文件。ENDFILE将生成有关空文件的信息,而另一种方法不会。