我有一个以分号分隔的数据文件,其中只有几行具有“完整”数据集。他们是在最后数据集适用的行块的位置。我想使用 shell 脚本(或类似的命令行工具)将数据从这个完整填充的行添加到上面的行。
例如,假设我的文件包含以下数据:
86540701
86951202
86262402
86509002
86770802
86459902
86301002
86485102
86556002;Vivo Y11;1630000;NULL;;;
86447404
86161405
86388604
86106105
86426405;Xiaomi Redmi 8A Pro (Redmi 8A Dual);1465000;4;;;
我希望能够找到完整的行并将该数据替换为上面不完整的行,如下所示:
86540701;Vivo Y11;1630000;NULL;;;
86951202;Vivo Y11;1630000;NULL;;;
86262402;Vivo Y11;1630000;NULL;;;
86509002;Vivo Y11;1630000;NULL;;;
86770802;Vivo Y11;1630000;NULL;;;
86459902;Vivo Y11;1630000;NULL;;;
86301002;Vivo Y11;1630000;NULL;;;
86485102;Vivo Y11;1630000;NULL;;;
86556002;Vivo Y11;1630000;NULL;;;
86447404;Xiaomi Redmi 8A Pro (Redmi 8A Dual);1465000;4;;;
86161405;Xiaomi Redmi 8A Pro (Redmi 8A Dual);1465000;4;;;
86388604;Xiaomi Redmi 8A Pro (Redmi 8A Dual);1465000;4;;;
86106105;Xiaomi Redmi 8A Pro (Redmi 8A Dual);1465000;4;;;
86426405;Xiaomi Redmi 8A Pro (Redmi 8A Dual);1465000;4;;;
答案1
这是一个我们可以使用的任务tac
以相反的顺序解析文件:
tac file | awk -F';' 'NF > 1 {p = substr($0,index($0,FS))} {print $1 p}' | tac
因此,我们不存储任何行,而是在读取每一行后进行打印。
当NF > 1
我们存储从行首FS
到行尾的子字符串以供将来使用时。
答案2
另一种awk
基于 的解决方案使用双通道方法(需要 GNUawk
或nawk
该gensub()
函数):
awk -F';' 'FNR==NR{if (NF>1) data[++i]=gensub(/^[^;]+/,"","1");next}
{if (NF==1) $0=$0 data[j+1]; else j++;} 1' input.csv input.csv
这将扫描文件两次。第一次,它创建包含多个字段的那些行的“数据部分”数组。第二次,它替换丢失的数据部分,并在每次遇到“完整”行时增加数组计数器,以便下一个数据部分替换后面的行。
答案3
使用sed
:
sed -E '
/;/!{ :a N;/;/!{ s/\n/-/;ta; }; };
/;/ { s/\n/-/; };
:c s/([^-]*)-([^;]*)(;.*)$/\1\3\n\2\3/; tc' infile
答案4
GNU sed
在打开扩展正则表达式模式的情况下使用-E
- 将记录存储在保留中,并在操作开始时等待分号记录。
- 当我们遇到分号线时,合并过程开始,其中模式空间的最后部分(=分号线)被附加到模式空间的第一部分,并且第一部分被打印并剥离。这一直持续到我们耗尽模式空间为止。
$ sed -Ee '/\n/ba
H;/;/!d;z;x;D;:a
s/\n(.*\n)?[^;]+(;.*)/\2&/
P;/\n.*\n/D;s/.*\n//
' file
$ perl -lne '$, = ";";
push(@A,$_),next if !/;/;
my $a = s/.*?;//r;
print $_, $a for splice @A;
print;
' file