【问题标题】:Bash: extract columns with cut and filter one column furtherBash:使用剪切提取列并进一步过滤一列
【发布时间】:2016-06-30 18:35:43
【问题描述】:

我有一个制表符分隔的文件,想用cut 提取几列。

两个示例行

(...)
0    0    1    0    AB=1,2,3;CD=4,5,6;EF=7,8,9    0    0
1    1    0    0    AB=2,1,3;CD=1,1,2;EF=5,3,4    0    1
(...)

我想要实现的是选择第 2、3、5 和 7 列,但仅从第 5 列中选择 CD=4,5,6

所以我的预期结果是

0    1    CD=4,5,6;    0
1    0    CD=1,1,2;    1

我如何使用 cut 来解决这个问题并在其中一个提取的列上运行 grep?任何其他的单线当然也可以。

【问题讨论】:

  • 一定要用cut吗? awk 会更好,因为您可以使用该列上的 split() 函数来提取其中的一部分。
  • 他说任何其他的单线也可以,所以你可以继续给他你的awk 答案
  • awk 也很好,我只是想先剪掉。

标签: bash awk grep cut


【解决方案1】:

这是另一个awk

$ awk -F'\t|;' -v OFS='\t' '{print $2,$3,$6,$NF}' file

0       1       CD=4,5,6        0
1       0       CD=1,1,2        1

或剪切/粘贴

$ paste <(cut -f2,3 file) <(cut -d';' -f2 file) <(cut -f7 file)

0       1       CD=4,5,6        0
1       0       CD=1,1,2        1

【讨论】:

  • 我最喜欢的解决方案是cutpaste
【解决方案2】:

使用awk 更容易完成。使用;作为分隔符拆分第5个字段,然后打印第二个子字段。

awk 'BEGIN {FS="\t"; OFS="\t"} 
     {split($5, a, ";"); print $2, $3, a[2]";", $7 }' inputfile > outputfile

如果要打印以CD= 开头的子字段,请使用循环:

awk 'BEGIN {FS="\t"; OFS="\t"} 
     {n = split($5, a, ";");
      for (i = 1; i <= n; i++) {
        if (a[i] ~ /^CD=/) subfield = a[i];
      }
      print $2, $3, subfield";", $7}' < inputfile > outputfile

【讨论】:

  • 如果第 5 个字段中的条目数量并不总是相同(并且并不总是包含CD=...),我会怎么做?
  • 所以您想打印第 5 个字段中以 CD= 开头的条目,而不总是第 2 个条目?这在问题中并不明显,因为结果与您的示例输入文件相同。
  • 确实是这样,谢谢指出,一开始我并不清楚。
【解决方案3】:

我认为awk 是完成此类任务的最佳工具,其他两个答案为您提供了很好的简短解决方案。

我想指出,您可以使用awk's 内置的拆分工具在解析输入时获得更大的灵活性。这是一个使用隐式拆分的示例脚本:

parse.awk

# Remember second, third and seventh columns
{
  a = $2
  b = $3
  d = $7
}

# Split the fifth column on ";". After this the positional variables
# (e.g. $1, # $2, ..., $NF) contain the fields from the previous
# fifth column
{
  oldFS = FS
  FS    = ";"
  $0    = $5
}

# For example to test if the second elemnt starts with "CD", do 
# something like this
$2 ~ /^CD/ {
  c = $2
}

# Print the selected elements
{
  print a, b, c, d
}

# Restore FS
{
  FS = oldFS
}

像这样运行它:

awk -f parse.awk FS='\t' OFS='\t' infile

输出:

0   1   CD=4,5,6    0
1   0   CD=1,1,2    1

【讨论】:

    猜你喜欢
    • 2023-04-05
    • 2018-11-24
    • 2020-04-10
    • 2021-09-11
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 2015-04-17
    • 1970-01-01
    相关资源
    最近更新 更多