【问题标题】:Incorporate variables into bash code line将变量合并到 bash 代码行中
【发布时间】:2012-01-23 23:18:28
【问题描述】:

也许这不是最好的标题;但是仅用简短的标题很难传达我的意图。

我这里有一行:

2   118610455   P2_PM_2_5034    T   <DUP:TANDEM>    40  .   END=118610566;SVLEN=110;SVTYPE=TDUP;CIPOS=-100,55;CIEND=-56,100;IMPRECISE;DBVARID=esv7540;VALIDATED;VALMETHOD=CGH;SVMETHOD=RP

基本上我想把它转换成:

2 118610455 118610566

所以主要问题是从第 8 列 grep 这个118610566

我知道如何 grep 这个数字:

$c=`cat line|awk '{print $8}'|sed 's/;/\t/g'|awk '{print $1}'|sed 's/\END=//g'`

但我的问题是如何将此变量合并到另一个 bash 行中:

what_i_want=`cat line|awk '{print $1"\t"$2"\t"$c}'`

谢谢

【问题讨论】:

    标签: bash variables awk


    【解决方案1】:

    也许这会有所帮助 -

    [jaypal:~/Temp] cat tmp
    2   118610455   P2_PM_2_5034    T   <DUP:TANDEM>    40  .   END=118610566;SVLEN=110;SVTYPE=TDUP;CIPOS=-100,55;CIEND=-56,100;IMPRECISE;DBVARID=esv7540;VALIDATED;VALMETHOD=CGH;SVMETHOD=RP
    
    [jaypal:~/Temp] var=$(awk -v FS="[ ;=]" '{print $1,$4,$24}' tmp)
    
    [jaypal:~/Temp] echo $var
    2 118610455 118610566
    

    FSawk's 内置变量。它默认为空格或制表符。由于您的行作为多个分隔符,将FS 设置为字符类有助于为每个分隔符拆分行。我们在这里定义的字符类是spacesemi-colonequal

    可能感觉有点奇怪,但当我碰巧解析超过 1 个分隔符的行时,我将它用作我的调试工具来识别列。这就是我从你的电话中得到的——

    [jaypal:~/Temp] awk -v FS="[ ;=]" '{for(i=1;i<=NF;i++) print "$"i" is "$i}' tmp
    $1 is 2
    $2 is 
    $3 is 
    $4 is 118610455
    $5 is 
    $6 is 
    $7 is P2_PM_2_5034
    $8 is 
    $9 is 
    $10 is 
    $11 is T
    $12 is 
    $13 is 
    $14 is <DUP:TANDEM>
    $15 is 
    $16 is 
    $17 is 
    $18 is 40
    $19 is 
    $20 is .
    $21 is 
    $22 is 
    $23 is END
    $24 is 118610566
    $25 is SVLEN
    $26 is 110
    $27 is SVTYPE
    $28 is TDUP
    $29 is CIPOS
    $30 is -100,55
    $31 is CIEND
    $32 is -56,100
    $33 is IMPRECISE
    $34 is DBVARID
    $35 is esv7540
    $36 is VALIDATED
    $37 is VALMETHOD
    $38 is CGH
    $39 is SVMETHOD
    $40 is RP
    

    你也可以通过下面的方式使用awk的一个简单的substr内置函数-

    [jaypal:~/Temp] awk '{print $1,$2,$8=substr($8,5,9)}' tmp
    2 118610455 118610566
    

    【讨论】:

    • 谢谢,但你能稍微解释一下 FS="[;=]" 吗?我不知道为什么 11861045 会变成第 4 列。
    【解决方案2】:

    只需一点点字符串操作,您就可以一次搞定。

    what_i_want=$(awk '{sub(/^END=/,"",$8); sub(/;.*$/,"",$8); print $1,$2,$8}' line)
    

    一些解释:

    sub(a,b,c) 在变量c 中搜索模式a 并将其替换为b,将修改后的字符串存储回c。模式写在//

    ^ 是字符串的开头,$ 是结尾,. 是任何东西,* 表示前面的模式的零个或多个。所以在我们的例子中:

    sub(/^END=/,"",$8); 匹配字符串开头的END= (^) 并用"" 替换它,什么都没有,本质上是删除它。

    sub(/;.*$/,"",$8); 将所有内容 (.*) 从 ; 带到末尾 ($) 并将其删除。请注意,在 awk 中,与大多数正则表达式引擎一样,*greedy,这意味着它需要最长的匹配,所以我们知道这将获得第一个 ;

    剩下的就是你想要的号码。

    【讨论】:

    • thx 效果很好......但是你能解释一下 sub(/;.*/,"",$8) 吗?我知道这里要截断之后的部分;正确的?但我不明白什么。和 * 在这里表示。
    【解决方案3】:

    如果你的“列”总是用空格分隔,那么你不需要使用 subshel​​ls 和 awk,你可以直接在 shell 中这样做:

    [ghoti@pc ~]$ read one two three four five junk <<< "2   118610455   P2_PM_2_5034    T   <DUP:TANDEM>    40  .   END=118610566;SVLEN=110;SVTYPE=TDUP;CIPOS=-100,55;CIEND=-56,100;IMPRECISE;DBVARID=esv7540;VALIDATED;VALMETHOD=CGH;SVMETHOD=RP"
    [ghoti@pc ~]$ echo "$five"
    <DUP:TANDEM>
    [ghoti@pc ~]$ echo "$junk"
    40 . END=118610566;SVLEN=110;SVTYPE=TDUP;CIPOS=-100,55;CIEND=-56,100;IMPRECISE;DBVARID=esv7540;VALIDATED;VALMETHOD=CGH;SVMETHOD=RP
    

    read 行上指定的最后一个变量将获得“其他所有内容”。

    还有。如果你正在处理这样的多行,你可以循环运行它:

    cat /path/to/inputfile | while read one two three four five junk; do
      echo "$one - $two - $five"
    done
    

    加盐调味。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-16
      • 1970-01-01
      • 1970-01-01
      • 2015-10-11
      • 1970-01-01
      • 1970-01-01
      • 2021-05-19
      • 2015-12-01
      相关资源
      最近更新 更多