在 Bash 中根据“_”分割列

在 Bash 中根据“_”分割列

您好,我有一个与此类似的问题邮政

但由于我是 Bash 新手,而且我的文件有点不同,我无法修改答案并将其应用到我的代码中。

我有一个包含多列的 csv 文件(所有列均以逗号分隔),我想要拆分的列如下所示:(输入文件)

post_id
86680728811_272953252761568
 86680728811_273859942672742
86680728811_281125741936891
86680728811_10150500662053812
_86680728811_10150500969563812
86680728811_10150501303143812
86680728811_305275689511038
_86680728811_10150501624593812
 86680728811_10150501873973812
86680728811_145945585518261

我想提取第二个 ID 号(下划线后面的那个)。请记住,有些列以数字开头,有些以空格开头,有些以“_”开头。

我想要的输出是添加两个新列,每个列包含由“_”分隔的 ID。第一行示例:

page ID             post ID 
86680728811         272953252761568

我尝试使用正则表达式来读取数字:

awk -F',' '{print $2} /(?<=_)[0-9]+/' FB_Dataset.csv

但到目前为止我所尝试的一切都不起作用。任何建议都会有所帮助。谢谢

答案1

awk -F', *_?' -v OFS=, '
  NR==1 {
    for (i=1;i<=NF;i++) {
      if ($i == "post_id") {
        $i = "page ID" OFS "post ID";
        col=$1;
      };
    };
    print;
    next
  };

  {
    split($col,a,/_/);
    $col=a[1] OFS a[2];
    print;
  };
  ' FB_Dataset.csv

由于您显示的字段数据的格式不一致(有些带有前导空格,有些以下划线开头,也许有些两者都有),因此此awk脚本使用正则表达式, *_?(“逗号后跟零个或多个空格,并且可选后跟下划线") 作为字段分隔符 ( FS)。

它还将输出字段分隔符 ( OFS) 设置为逗号。

读取输入时,它以不同的方式处理第一行(CSV 标题)和所有剩余行:

对于第一行 ( NR==1),它检查每个字段的值,查找字符串"post_id"。如果找到该字符串,它会更改该字段的值,以便它具有两个新的字段名称(page IDpost ID),并以OFS.它还将该字段的索引号存储在变量中col以供以后使用。最后,它打印修改后的行。

这假定字段名称是唯一的,因为它们对于有效的 CSV 文件应该是唯一的。如果多个字段具有 name ,它将无法正常工作post_id

对于其余行,它使用下划线 ( ) 字符作为分隔符将字段拆分$col为数组。然后,它将 $col 替换为该数组的前两个元素,并用.然后它打印修改后的行。a_OFS

输入示例:

A,B,C,post_id,D,E,F
a,b,c,86680728811_272953252761568,d,e,f
a,b,c, 86680728811_273859942672742,d,e,f
a,b,c,86680728811_281125741936891,d,e,f

示例输出:

A,B,C,page ID,post ID,D,E,F
a,b,c,86680728811,272953252761568,d,e,f
a,b,c,86680728811,273859942672742,d,e,f
a,b,c,86680728811,281125741936891,d,e,f

在标题行中,该post_id字段已转换为两个字段(page IDpost ID),并且在 CSV 数据中,相应的字段已拆分为两个字段。

顺便说一句,因为脚本post_id在标题行中搜索匹配的字段名称 ( ),所以它可以处理我们要拆分的字段之前和/或之后的任意数量的字段。通过这个样本数据,发现第四个字段包含了我们想要的名称,所以col=4


请注意,$i$col在 awk 中的含义与在 shell 中的含义不同。

  • 在 shell 中,它们意味着以下变量:名字icol
  • 在 中awk,它们的意思是“索引号等于变量值的字段的值i(或变量col)”。即它通过间接访问字段。

    例如 if i=1then$i表示“字段 1 中的值”,与 相同$1

    例如,如果您需要对字段编号执行算术运算,则这非常有用。在 awk 中,NF是一个自动创建的变量,包含当前输入行最后一个字段的索引号。 so$NF表示“最后一个字段中的值”,and$(NF-1)表示“倒数第二个字段中的值”,依此类推。

答案2

这对你有用吗?我将假设这种格式:

A B C post_id
a,b,c,86680728811_272953252761568
a,b,c, 86680728811_273859942672742
a,b,c,86680728811_281125741936891
a,b,c,86680728811_10150500662053812
a,b,c,_86680728811_10150500969563812
a,b,c,86680728811_10150501303143812
a,b,c,86680728811_305275689511038
a,b,c,_86680728811_10150501624593812
a,b,c, 86680728811_10150501873973812
a,b,c,86680728811_145945585518261

然后是命令

cat file | sed -Ee 's/(.*)post_id/\1page ID post I/' -e 's/,[_ ]/,/' -e 's/_/,/'

输出:

A B C page ID post ID
a,b,c,86680728811,272953252761568
a,b,c,86680728811,273859942672742
a,b,c,86680728811,281125741936891
a,b,c,86680728811,10150500662053812
a,b,c,86680728811,10150500969563812
a,b,c,86680728811,10150501303143812
a,b,c,86680728811,305275689511038
a,b,c,86680728811,10150501624593812
a,b,c,86680728811,10150501873973812
a,b,c,86680728811,145945585518261

-E使用扩展正则表达式(GNU),可以捕获组。


更改标题以添加page ID post ID捕获第一个组(.*)直到post_id,并将其替换为捕获的组\1page ID post ID

's/(.*)post_id/\1page ID post ID/'

_从逗号后面的行中删除前导空格和下划线,并将其替换为单个逗号。

sed 's/,[_ ]/,/'

最后,将下划线替换_为逗号。

sed 's/_/,/'

请注意,我删除了cut不必要的命令(这是我尝试过的其他命令的提醒)

答案3

我会用:

awk -F' *_?' '{ print $(NF-1), $NF }' infile

相关内容