![在 Bash 中根据“_”分割列](https://linux22.com/image/160976/%E5%9C%A8%20Bash%20%E4%B8%AD%E6%A0%B9%E6%8D%AE%E2%80%9C_%E2%80%9D%E5%88%86%E5%89%B2%E5%88%97.png)
您好,我有一个与此类似的问题邮政
但由于我是 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 ID
和post 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 ID
和post ID
),并且在 CSV 数据中,相应的字段已拆分为两个字段。
顺便说一句,因为脚本post_id
在标题行中搜索匹配的字段名称 ( ),所以它可以处理我们要拆分的字段之前和/或之后的任意数量的字段。通过这个样本数据,发现第四个字段包含了我们想要的名称,所以col=4
请注意,$i
和$col
在 awk 中的含义与在 shell 中的含义不同。
- 在 shell 中,它们意味着以下变量:名字是
i
和col
。 在 中
awk
,它们的意思是“索引号等于变量值的字段的值i
(或变量col
)”。即它通过间接访问字段。例如 if
i=1
then$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
,并将其替换为捕获的组\1
和page ID post ID
's/(.*)post_id/\1page ID post ID/'
_
从逗号后面的行中删除前导空格和下划线,并将其替换为单个逗号。
sed 's/,[_ ]/,/'
最后,将下划线替换_
为逗号。
sed 's/_/,/'
请注意,我删除了cut
不必要的命令(这是我尝试过的其他命令的提醒)
答案3
我会用:
awk -F' *_?' '{ print $(NF-1), $NF }' infile