有谁知道我如何“拆分”下面的行(这只是一个例子):
mercedes|$40000|black|$42000|white|$41000|red
audi|$31000|blue|$10000|white
mercedes|$5000|blue
我期望的输出是:
mercedes|$40000|black
mercedes|$42000|white
mercedes|$41000|red
audi|$31000|blue
audi|$10000|white
mercedes|$5000|blue
谢谢
答案1
一个简单的awk
脚本,用于从第二个字段开始的每行输出字段对,并为每个输出对添加该行的第一个字段作为前缀。
$ awk -F '|' 'BEGIN { OFS=FS } { for (i = 2; i+1 <= NF; i += 2) print $1, $i, $(i+1) }' file
mercedes|$40000|black
mercedes|$42000|white
mercedes|$41000|red
audi|$31000|blue
audi|$10000|white
mercedes|$5000|blue
这假设输入符合预期,即最终数据应组织为三列。这意味着输入应严格遵循
title|pair 1a|pair 1b|pair 2a|pair 2b|...|pair Na|pair Nb
答案2
awk -F'[|]' '{ for(i=3; i<NF; i+=2) sub($i, $i ORS $1) }1' infile
请注意,第一个参数sub(regexp, replacement [, target])
功能是个正则表达式所以它将把 the$i
视为正则表达式。
另请参阅更多关于'\' 和 '&' 与 sub()、gsub() 和 gensub() 函数当谈到这些函数的第二个参数时也是如此。
或者,按照以下方式执行,而不会出现上述 sub() 问题:
awk 'BEGIN{ FS=OFS="|" } { for(i=3; i<NF; i+=2) $i= $i ORS $1 }1' infile
答案3
python
与itertools
模块一起重复提供第一个字段以填充前两个字段。
python3 -c 'import sys
import itertools as it
ifile = sys.argv[1]
ofs = fs = "|"
with open(ifile) as f:
for l in f:
L = l.rstrip("\n").split(fs)
for a,b in zip(it.repeat(L.pop(0)),zip(*[iter(L)]*2)):
print(a,*b,sep=ofs)
' file
perl
也可以用于我们打印前导第 2+3 个字段以及第一个字段,然后删除第 2 个和第 3 个字段,从而允许下一个字段取代它们的位置。
perl -F'[|]' -lane '$,="|";
print $F[0], splice(@F,1,2)
while @F > 3;
print @F;
' file
GNU sed
启用扩展正则表达式模式-E
。
- 标记到第三个字段的末尾,准备从字段 1 到字段 3 进行打印。
- 复制第三个字段后的第一个字段,为下一轮打印做准备。
sed -Ee '
s/[|]/\n/3;P
s/^([^|]+[|]).*\n/&\1/;D
' file
解释:
- 想象一条像这样的线:
- 汽车品牌 | p1 | c1 | p2| c2 | ... |上 |中文
- 我们希望品牌与价格/颜色元组单独在一条线上配对。
- 将第三个管道分隔符替换为换行符:
s/[|]/\n/3
- 现在可视化模式空间:
- 汽车品牌 | p1 | c1 \n p2 | c1 \n p2 | c1 \n p2 | 2 | ... |上 |中文
- sed 命令
P
(大写 pee)打印到标准输出,直到第一个换行符。 - 到此阶段的输出为:
- 汽车品牌 | p1 | c1
- 第一对价格/颜色的使用就结束了。现在需要做的是将汽车品牌复制到下一个价格/颜色对:
s/^([^|]+[|]).*\n/&\1/
- 括号记住匹配的内容,即:前导数据,包括第一个管道分隔符。我们匹配直到换行。替换部分是与我们记忆中的(汽车品牌|)相匹配的部分(&)。
- 模式空间现在看起来像 Car_brand | p1 | c1 \n 汽车品牌 | p2| c2 | ... | l pn |中文
- 这Delete 命令一直持续到第一个换行符
- 模式空间现在变成了 Car _brand | p2| c2 | ..| PN |中文
- 该命令的属性
D
是,在删除直到第一个换行符并提供剩余内容后,它将 sed 代码重新应用到剩余的模式空间。 - 简而言之,这相当于一个循环动作。
结果:
mercedes|$40000|black
mercedes|$42000|white
mercedes|$41000|red
audi|$31000|blue
audi|$10000|white
mercedes|$5000|blue
答案4
和perl
:
perl -F"\|" -le '$,="|";
for (my $a=1;$a<@F;$a+=2)
{print $F[0],$F[$a], $F[$a+1]}' input
-F"\|"
输入字段分隔符设置为|
$,="|";
输出字段分隔符设置为|
$a<scalar @F;
这里scalar @F
告诉了字段的总数,$a<scalar @F
因为 Perl 中的字段从零开始。
这是答案由 @Kusalananda 但在perl
.