【问题标题】:Extract numbers from tab-delimited files从制表符分隔的文件中提取数字
【发布时间】:2021-12-21 20:11:54
【问题描述】:

我有一个制表符分隔的 .txt 文件,它有 4 行和 4 列。我想从 txt 文件中提取数字(整数、十进制数和科学记数法)。数字在第 2-4 行和第 2-4 列(第一行是标题,第一列是行名)。 文件内容粘贴在下面:

component   sigma          h2           h2_se
G           -5.55758e-19   -0.0964725   26.3887
GxE         6.13144e-18    1.09647      26.3651
noise       0              0            0

这是所需的输出,由于对此输出的进一步处理,我想在末尾附加换行符\n

-5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0

非常感谢任何帮助!

以下是我尝试的一些代码,但没有产生我想要的:

grep -o '0.[[:digit:]]*' myfile

grep -o '[[:digit:]]*' myfile

================================================ =====

这是对我有用的代码,非常感谢@tink!

awk 'NR>1 {printf "%s %s %s ", $2,$3,$4}END{printf "\n"}' myfile

【问题讨论】:

  • 到目前为止,您尝试过什么来解决这个问题?请在帖子中包含任何相关代码。
  • @tink 嘿,它现在可以工作了——我用错误的文件名运行它(因此格式错误),然后我改成了awk 'NR>1 {printf "%s %s %s ", $2,$3,$4}END{printf "\n"}',因为只有第一行是不需要的。非常感谢您的帮助!
  • 这将在输出中添加一个尾随空白。 print "" 也比 printf "\n" 好,因为前者只是使用 ORS 而后者使用它希望将 ORS 设置为的硬编码字符串。
  • 请将答案作为答案发布在社区可以投票/否决的地方,并显示为搜索论坛的人的答案,不要只将答案包含在您的问题中,并且显然没有答案。

标签: regex linux awk grep


【解决方案1】:
$ awk 'NR>1{$1=""; out=out $0} END{$0=out; $1=$1; print}' file
-5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0

或者,其中任何一个也可以工作:

$ awk 'NR>1{printf "%s%s %s %s", sep, $2, $3, $4; sep=OFS} END{print ""}' file
-5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0

$ awk 'NR>1{printf "%s%s %s %s", (NR>2 ? OFS : ""), $2, $3, $4} END{print ""}' file
-5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0

如果您的第一个字段可以包含空白,则在脚本开头添加 -F'\t'

【讨论】:

  • 这里有一些解释:NR>1{ ... }:只有在我们不处理第一行/记录时才执行此操作。 $1="" 清空第一个字段并将记录 $0 重建为 $1 OFS $2 OFS $3 OFS $4OFS 一个空格。 out = out $0 后缀变量out 与记录。 END{...} 在到达文件末尾时执行此操作。 $0=outout 分配给当前记录并进行字段拆分。请注意,当前记录以空格开头。 $1=$1 将记录 $0 重建为 $1 OFS $2 OFS $3,这是摆脱第一个空格的迷人方式。 print打印当前记录$0
  • 注意:如果文件的第一列有空格,这将失败。
【解决方案2】:
$ cut -f2- < file | tail -n+2 | paste -s - | tr '\t' ' '
-5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0

【讨论】:

  • 很好地使用了剪切和粘贴,尤其是它们在默认情况下处理制表符分隔的文件时。
【解决方案3】:

以下grep 提取所有整数或实数单词:

$ grep -owE '[-+]?[0-9]*([.][0-9]*([Ee][-+][0-9]+)?)?' file | tr '\n' ' '

这只是由于您输入文件的性质而起作用。

一种稳健的方法,是 Ed Morton here 提出的 awk 程序

【讨论】:

    【解决方案4】:

    我会使用 GNU AWK 来完成这个任务,让 file.txt 内容成为

    component   sigma          h2           h2_se
    G           -5.55758e-19   -0.0964725   26.3887
    GxE         6.13144e-18    1.09647      26.3651
    noise       0              0            0
    

    然后用单个\t 分隔字段

    awk 'BEGIN{ORS=""}NR>1{$1="";print}' file.txt
    

    输出

     -5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0
    

    说明:我通知 GNU AWK 使用空字符串作为输出行分隔符 (ORS),然后对于第一行之后的每一行,我将第一个字段设置为空字符串和 print 这样更改的行。请注意,输出字符串有前导空格并且末尾没有换行符,如果您需要换行符添加END{print "\n"}

    (在 GNU Awk 5.0.1 中测试)

    或者,您可以通过管道传递一些 linux 实用程序以获得类似的效果,如下所示

    tail -3 file.txt | cut -f 2,3,4 | tr '\n\t' '  '
    

    输出

    -5.55758e-19 -0.0964725 26.3887 6.13144e-18 1.09647 26.3651 0 0 0 
    

    说明:使用tail 获取最后3 行,然后通过cut 获取列2,3,4,然后使用tr 将换行符更改为空格,将制表符更改为空格。

    【讨论】:

      【解决方案5】:

      这是对我有用的代码,非常感谢@tink!为下一步处理添加\n

      awk 'NR&gt;1 {printf "%s %s %s ", $2,$3,$4}END{printf "\n"}' myfile

      对于没有尾随空格的输出,使用

      awk 'NR&gt;1 {printf "%s %s %s ", $2,$3,$4}' myfile

      【讨论】:

      • 这两个脚本都输出尾随空格,第二个只是不输出终止换行符,因此不是有效的 POSIX 文本文件。
      • @EdMorton 我明白了!感谢您指出了这一点。你能检查一下我在编辑后的帖子中是否正确吗?
      • 不,您看到"%s %s %s " 末尾的空格了吗?那是您要打印的尾随空格。你需要一种不同的方法来避免它,例如请参阅我刚刚更新的答案,以展示如何按照您在答案中所做的那样对字段进行硬编码打印,但使用终止换行符并且没有尾随空格。
      猜你喜欢
      • 2012-08-19
      • 2019-10-01
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 2012-12-01
      • 2016-09-20
      • 1970-01-01
      • 2016-05-21
      相关资源
      最近更新 更多