将最后一个字段替换为前一个字段

将最后一个字段替换为前一个字段

我有一个如下所示的文件:

10-04-2022 00:39:13,36707,1455008753,32
11-05-2022 00:39:13,36708,1555008753,26
21-05-2022 00:39:13,36708,1555408753,15
12-06-2022 00:39:13,36709,1655008753

因为最后一个字段的值与下一行的运行时间相关,所以我想将它们向下移动到这种方式以便与 gnuplot 一起使用。

10-04-2022 00:39:13,36707,1455008753,
11-05-2022 00:39:13,36708,1555008753,32
21-05-2022 00:39:13,36708,1555408753,26
12-06-2022 00:39:13,36709,1655008753,15

答案1

一个简单的 awk 脚本可以做到这一点:

awk 'BEGIN {FS=OFS=","} { tmp=$NF; $NF=save; print; save=tmp; }' < input > output

这会将第四个字段保存到临时变量中,用之前保存的值替换第四个字段,然后打印新行。打印后,它会保存第四个字段的先前值以供下一次迭代使用。在第一行,“save”d值为空(默认的awk行为),这达到了预期的结果。

“BEGIN”部分将字段分隔符(用于分割输入)和输出字段分隔符(在打印行/字段时使用)设置为逗号。请参阅本地awk手册页、各种在线参考资料或awk 的开放组基本规范了解更多。

答案2

另一个awk解决方案,在 GNU awk5.1.0 上测试。

$ awk -F, -v OFS=, '{print $1,$2,$3,x;x=$NF}' myfile
10-04-2022 00:39:13,36707,1455008753,
11-05-2022 00:39:13,36708,1555008753,32
21-05-2022 00:39:13,36708,1555408753,26
12-06-2022 00:39:13,36709,1655008753,15
$

答案3

使用(以前称为 Perl_6)

raku -e 'my @a = lines>>.split(","); my $m = @a>>.elems.max;  \
         .flat.join(",").put for [Z] @a>>.[0..$m-2], ("", @a>>.[$m-1]).flat;'

或者

raku -e 'my @a = lines.map: *.split(","); my $m = @a.map(*.elems).max;  \
         .flat.join(",").put for [Z] @a.map(*.[0..$m-2]), ("", @a.map: *.[$m-1]).flat;' 

这个 Raku 答案有点长,但也更像是一个通用解决方案,因为每行的列数不是硬编码的:max计算文件范围。

简而言之(两个例子),lines都是读入的,每个都split,逗号分隔,并存储在@a数组中。计算许多(列)并将其存储max为。然后,使用 Raku 的“Zip Reduction”运算符从其后面的两个列表中逐一拉出元素:这些元素在 out 中被整理并重新组合在一起,这样现在一个空字符串占据了第一个列表的末尾行,后续索引值将向下移动一行。elems$m[Z]flatjoinput""@a[$m-1]注意:Raku 不会自动展平数组元素,因此您必须flat手动将它们展平为十个(如果需要)。

在这两个例子中,我试图展示 Raku 的>>“超级”运算符如何类似于map对单个元素执行 ping 函数/索引,或者.map(*.fn)(在方法链的末尾)使用冒号形式.map: *.fn;,这可以减少数量所需的括号数。

输入示例:

10-04-2022 00:39:13,36707,1455008753,32
11-05-2022 00:39:13,36708,1555008753,26
21-05-2022 00:39:13,36708,1555408753,15
12-06-2022 00:39:13,36709,1655008753

示例输出:

10-04-2022 00:39:13,36707,1455008753,
11-05-2022 00:39:13,36708,1555008753,32
21-05-2022 00:39:13,36708,1555408753,26
12-06-2022 00:39:13,36709,1655008753,15

附录:这是另一种 Raku 方法,这次将行/列展开为单独的元素,并使用rotor.它给出与上面完全相同的结果:

raku -e 'my @a = lines>>.split(",").flat; my @b = @a[3,7,11...*];  \
         @a.=rotor(3 => 1); @a.=map(*.join(",")); @b.=unshift(""); \
        .join(",").put for [Z] @a, @b;' 

https://docs.raku.org/language/operators#index-entry-[]_(reduction_metaoperators)
https://docs.raku.org/language/operators#index-entry-hyper_method_call_operator
https://docs.raku.org/routine/flat

答案4

使用 GNU sed 的扩展正则表达式模式来简化正则表达式的编写,我们的方法是在模式空间中随时维护两行。然后将上一行的倒数第二个字段移至当前行末尾。

sed -E '
  1s/$/,/
  $!N
  s/(,[^,]+)(,[^,]*\n.*)/\2\1/
  P;D
' file

输入:-

10-04-2022 00:39:13,36707,1455008753,32
11-05-2022 00:39:13,36708,1555008753,26
21-05-2022 00:39:13,36708,1555408753,15
12-06-2022 00:39:13,36709,1655008753#

输出:-

10-04-2022 00:39:13,36707,1455008753,
11-05-2022 00:39:13,36708,1555008753,32
21-05-2022 00:39:13,36708,1555408753,26
12-06-2022 00:39:13,36709,1655008753#,15

相关内容