在sh中分割和处理文本文件

时间:2019-03-14 13:42:20

标签: bash shell awk

我有一个带有逗号(,)分隔符的文本文件:

60,tel:+33xxxxxxx,840191,1,0,tel:+33xxxxxxx;kn-corp-groups=3_6,8401
61,tel:+33xxxxxxx,840191,1,1,tel:+33xxxxxxx;kn-corp-groups=4_60,8401
60,tel:+33xxxxxxx,840191,1,0,tel:+33xxxxxxx;kn-corp-groups=3_5,8401
61,tel:+33xxxxxxx,840191,1,1,tel:+33xxxxxxx;kn-corp-groups=1_59,8401

我想获取输出:

60,tel:+33xxxxxxx,840191,1,0,3,6,8401
61,tel:+33xxxxxxx,840191,1,1,4,60,8401
60,tel:+33xxxxxxx,840191,1,0,3,5,8401
61,tel:+33xxxxxxx,840191,1,1,1,59,8401

例如,对于每一行,我将“ 3,6”中的字段“ tel:+ 33xxxxxxx; kn-corp-groups = 3_6”展平。

您对我该怎么做有任何想法吗? 谢谢

7 个答案:

答案 0 :(得分:3)

对于此数据:

$ awk 'BEGIN{FS="[,_=]";OFS=","}{print $1,$2,$3,$4,$5,$7,$8,$9}' file

输出:

60,tel:+33xxxxxxx,840191,1,0,3,6,8401
61,tel:+33xxxxxxx,840191,1,1,4,60,8401
60,tel:+33xxxxxxx,840191,1,0,3,5,8401
61,tel:+33xxxxxxx,840191,1,1,1,59,8401

解释:

$ awk 'BEGIN{
    FS="[,_=]"                    # use multiple chars as field separators
    OFS=","
}
{
    print $1,$2,$3,$4,$5,$7,$8,$9
}' file

答案 1 :(得分:0)

能否请您尝试以下操作,如果我做对了,您需要提取其中包含字符串tel:+33xxxxxxx的行。

awk -F'[,_=]' 'BEGIN{OFS=","} /tel:\+33xxxxxxx/{print $1,$2,$3,$4,$5,$7,$8,$9}'  Input_file


第二种解决方案: :如果您不想硬编码(这些值可能在Input_file中的任何地方),请尝试输入字段号。

awk '
BEGIN{
  OFS=","
}
match($0,/^[0-9]+\,tel:\+33xxxxxxx\,[0-9]+\,[0-9]+\,[0-9]+/){
  val=substr($0,RSTART,RLENGTH)
  match($0,/kn-corp-groups=[0-9]+_[0-9]+\,[0-9]+/)
  val1=substr($0,RSTART+15,RLENGTH-15)
  sub("_",",",val1)
  print val,val1
  val=val1=""
}'   Input_file

输出如下。

60,tel:+33xxxxxxx,840191,1,0,3,6,8401
61,tel:+33xxxxxxx,840191,1,1,4,60,8401
60,tel:+33xxxxxxx,840191,1,0,3,5,8401
61,tel:+33xxxxxxx,840191,1,1,1,59,8401

答案 2 :(得分:0)

使用gawk

awk 'BEGIN{ FS=OFS="," } NF {$(NF-1) = gensub(/.*=(.*)_/, "\\1,", 1, $(NF-1))}1' file

这里,我们只需要使用$(NF-1)gensub()处理最后一列NF的下一个,就可以跳过EMPTY行。

答案 3 :(得分:0)

$ sed 's/[^,]*;[^,]*\([0-9]*\)_/\1,/' file
60,tel:+33xxxxxxx,840191,1,0,3,6,8401
61,tel:+33xxxxxxx,840191,1,1,4,60,8401
60,tel:+33xxxxxxx,840191,1,0,3,5,8401
61,tel:+33xxxxxxx,840191,1,1,1,59,8401

答案 4 :(得分:0)

sed

awk 已被其他答案覆盖。这是使用 sed 的替代方法:

$ sed -E -e 's/[^,]+;[^=]+=//' -e 's/_/,/' file

说明

  • sed -E,以便使用扩展的正则表达式
  • sed -e执行sed脚本。请记住,将sed脚本括在单引号(')中,以防止外壳扩展外壳程序。我们将需要执行两个脚本。

  • s/[^,]+;[^=]+=//这两个脚本中的第一个。剥离不需要的字符串( tel:+ 33xxxxxxx; kn-corp-groups = ):

    • 替代(s/
    • 一个或多个不是逗号([^,]+)的字符
    • 后跟一个分号(;
    • 后跟一个或多个非等号([^=]+)的字符
    • 后跟一个等号(=
    • 一无所有,即删除匹配的字符串(//)。
  • s/_/,/这两个脚本中的第二个。将两个数字之间的下划线(_)替换为逗号(,):
    • 替换(s/
    • 下划线(_
    • 带有逗号(/,/)。

替代项

更多没有awk的shell选择:

  • sed管道
    这两个 sed 脚本也可以与管道一起使用:
    $ sed -E 's/[^,]+;[^=]+=//' file | sed 's/_/,/'
    这会降低效率,但是如果不关心速度,则有些人可能会更容易理解。有关详细信息,请参见this answer
  • sed + tr
    上面管道的第二部分可以通过简单的tr命令进行交换:
    $ sed -E 's/[^,]+;[^=]+=//' file | tr '_' ','
  • tr + cut
    我们也可以不用sed:
    $ tr '=_' ',' < file | cut -d, -f 1-5,7-9
    在这里,我们首先使用=_,替换为tr,以便用逗号分隔字段,
    并用cut打印除第六个字段以外的所有字段(-d表示定界符,-f表示我们要打印的字段,即除6)。
  • sed组字幕
    另请参阅Ed Morton's answer,其中使用sed的组标题。

答案 5 :(得分:0)

使用Perl正则表达式

perl -pe ' s/(.*)(tel:.*=)(.*)_(.*)/$1$3,$4/ ' file

使用您给定的输入

$ cat shakile.txt
60,tel:+33xxxxxxx,840191,1,0,tel:+33xxxxxxx;kn-corp-groups=3_6,8401
61,tel:+33xxxxxxx,840191,1,1,tel:+33xxxxxxx;kn-corp-groups=4_60,8401
60,tel:+33xxxxxxx,840191,1,0,tel:+33xxxxxxx;kn-corp-groups=3_5,8401
61,tel:+33xxxxxxx,840191,1,1,tel:+33xxxxxxx;kn-corp-groups=1_59,8401

$ perl -pe ' s/(.*)(tel:.*=)(.*)_(.*)/$1$3,$4/ ' shakile.txt
60,tel:+33xxxxxxx,840191,1,0,3,6,8401
61,tel:+33xxxxxxx,840191,1,1,4,60,8401
60,tel:+33xxxxxxx,840191,1,0,3,5,8401
61,tel:+33xxxxxxx,840191,1,1,1,59,8401

$

答案 6 :(得分:0)

awk '{sub(/_/,",")}{print (substr($0, 1,29) substr($0, 60))}' file

60,tel:+33xxxxxxx,840191,1,0,3,6,8401
61,tel:+33xxxxxxx,840191,1,1,4,60,8401
60,tel:+33xxxxxxx,840191,1,0,3,5,8401
61,tel:+33xxxxxxx,840191,1,1,1,59,8401