【问题标题】:shall script: merge files, how to add some characters at the beginning of each line of awk outputshell脚本:合并文件,如何在awk输出的每一行开头添加一些字符
【发布时间】:2021-06-10 01:00:11
【问题描述】:

我正在尝试使用 bash 脚本将数百个包含物种名称和比例的样本文件合并到一个长格式文件中。我想知道如何在每行 awk 输出的开头添加一些字符。

我在变量$STEM 中保存了一些sampleID。我使用awk 从每个文件中获取物种名称和比例。比例在每一行的开头;物种名称在每行的末尾(第 6 位)(制表符分隔)。但我还想将 sampleID ($STEM) 添加到输出文件中每一行的开头。这是我的代码:

for file in $input_dir/*_species_abundance.txt
do
        STEM=$(basename "$file" _species_abundance.txt )
        echo "processing sample $STEM"
        awk '{print "$STEM," $1,$6}' FS='\t' $file >> $input_dir/merged_species_abundance.txt

done

"$STEM," 部分无法按预期工作,因为当前输出是“$STEM”,而不是用 sampleID 替换它。

您对如何修改代码有什么建议吗?提前谢谢!

这是一些示例输入:

  0.45  124078  0       S       148633                s__Faecalibacterium prausnitzii_D
  0.35  95476   0       S       145938                s__Faecalibacterium prausnitzii_C
  0.21  57002   0       S       158191                s__Faecalibacterium prausnitzii_I
  0.18  49503   0       S       224832                s__Faecalibacterium sp900539945
  0.07  18991   0       S       157095                s__Faecalibacterium prausnitzii_G
  0.04  12007   0       S       187396                s__Faecalibacterium prausnitzii_F
...
... 

第一个数字是比例,最后一个是物种名称。

sampleID 类似于 1001, 1002, 1003, ...

我想要的输出是(逗号分隔):

1001,0.45,s__Faecalibacterium prausnitzii_D
1001,0.35,s__Faecalibacterium prausnitzii_C
1001,0.21,s__Faecalibacterium prausnitzii_I
...
1002,0.28,s__Faecalibacterium prausnitzii_D
1002,0.00,s__Faecalibacterium prausnitzii_C
1002,0.01,s__Faecalibacterium prausnitzii_I
...
1003,0.60,s__Faecalibacterium prausnitzii_D
1003,0.02,s__Faecalibacterium prausnitzii_C
1003,0.39,s__Faecalibacterium prausnitzii_I
...
...

【问题讨论】:

  • TLDR 但是从您的awk 代码的简单一瞥,它只需要一个-v 标志来分配shell 变量。 awk -v var="$STEM" '{print var, $1,$6} ....
  • this 会回答您的问题吗?顺便说一句,我还建议切换到小写或混合大小写的 shell 变量,以避免与许多对 shell 和/或某些命令具有特殊含义的全大写名称发生意外冲突。
  • @GordonDavisson 谢谢!我在 awk 命令中搜索 -v 选项。该链接非常有帮助。并感谢您的提醒。我的同事使用 STEM 作为变量名,所以我一直使用它......我一定会记住你的提示!

标签: bash awk command-line merge


【解决方案1】:

我想这就是你要找的东西:

input_dir=mydir;
for file in $input_dir/*_species_abundance.txt;
do
    STEM=$(basename "$file" _species_abundance.txt );
    echo "processing sample $STEM";
    awk '{print '$STEM' "," $1 "," $6 " " $7}' $file; >> $input_dir/merged_species_abundance.txt
done

打印shell环境变量$STEM的值的关键是让shell通过“将它放在单引号之外”来评估它,'。然后,awk 得到它的值。

这是生成的输出:

processing sample 1001
processing sample 1002
processing sample 2001
processing sample 2002
$ cat mydir/merged_species_abundance.txt
1001,0.45,s__Faecalibacterium prausnitzii_D
1001,0.35,s__Faecalibacterium prausnitzii_C
1001,0.21,s__Faecalibacterium prausnitzii_I
1001,0.18,s__Faecalibacterium sp900539945
1001,0.07,s__Faecalibacterium prausnitzii_G
1001,0.04,s__Faecalibacterium prausnitzii_F
1002,0.45,s__Faecalibacterium prausnitzii_D
1002,0.35,s__Faecalibacterium prausnitzii_C
1002,0.21,s__Faecalibacterium prausnitzii_I
1002,0.18,s__Faecalibacterium sp900539945
1002,0.07,s__Faecalibacterium prausnitzii_G
1002,0.04,s__Faecalibacterium prausnitzii_F

【讨论】:

  • 这取决于样本 ID 是否为数字;将其作为 awk 变量传递(如 @Jetchisel 的评论中所示)更安全。
  • 谢谢!单引号有效!我也会尝试将它作为 awk 变量传递。请问为什么使用 awk 变量更安全?
  • @GordonDavisson,它不依赖于样本 ID 是否为数字。它可以包括文本。我刚刚用一个名为he's__species_abundance.txt 的文件对其进行了测试,它运行良好:he's_,0.18,s__Faecalibacterium sp900539945。请注意,我在名称中包含了 ' 以使其变得怪异。我想它可能无法处理一些陌生字符,如果它们位于名称的第一部分,但我认为这不太可能。
  • @LuisGuzman 在我测试过的awk 的任何版本上,它都不适用于该文件名(我不知道它是怎么做到的)。我收到awk: 1: unexpected character '''awk: syntax error at source line 1 之类的错误。为了让它工作,我必须添加双引号(在单引号内),比如:awk '{print "'$STEM'" ...。但是为了保护变量免受 shell 处理,它应该在双引号中(在单引号之外),例如:awk '{print "'"$STEM"'" ...。在某些情况下,这仍然会失败。
  • @GordonDavisson,它确实适用于我的 ol7 linux vm 上的 awk,但我明白你的意思。名称上的不寻常字符可能会破坏它。此外,我了解与代码注入相关的安全问题,这在某些环境中可能是一个问题。我不反对-v 选项。在编写需要考虑上述问题的脚本时,这是要走的路。也就是说,对于我的日常使用以及我为使我的办公室生活更轻松而编写的脚本而言,这通常不是问题,我也不会打扰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
  • 2018-02-05
  • 1970-01-01
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
  • 2010-10-04
相关资源
最近更新 更多