根据第二个字段的重复值将字符附加到字段记录

根据第二个字段的重复值将字符附加到字段记录

我有这个输入

array='2       0.00000         -1.45191
6       0.81778         -0.63413
10      0.85020         -0.60170
8       1.40260         -0.04931
22      3.25781         1.80590
20      4.32051         2.86860
6       0.00000         -0.93906
18      0.07618         -0.86288
8       0.36922         -0.56984
12      0.71195         -0.22711
16      0.88517         -0.05389'

我正在尝试复制相同的数组,但如下所示,

2       0.00000         -1.45191
6       0.81778         -0.63413
10      0.85020         -0.60170
8       1.40260         -0.04931
22      3.25781         1.80590
20      4.32051         2.86860
6-      0.00000         -0.93906
18-     0.07618         -0.86288
8-      0.36922         -0.56984
12-     0.71195         -0.22711
16-     0.88517         -0.05389

不同之处在于,$1使用第二个字段的第二个值作为指示符0.00000为第一个字段的第二部分添加后缀。$2如果可以使用该awk命令,我会很高兴。

答案1

根据你的例子,你出现想要做的是在第二列中记录字符串0.00000(或可能是数值)的出现次数,并在计数达到 2 时附加到第一列的值:0-

printf '%s\n' "$array" | awk '$2 == "0.00000" {++ind} ind == 2 {$1 = $1"-"} 1'

但是,这会将满足条件的记录中的列分隔符替换为默认(单个空格)输出分隔符。如果您的输入分隔符是空格字符序列,那么保留对​​齐的一种方法是将第一个空格字符替换为-

$ printf '%s\n' "$array" | awk '$2 == "0.00000" {++ind} ind == 2 {sub(/ /,"-")} 1'
2       0.00000         -1.45191
6       0.81778         -0.63413
10      0.85020         -0.60170
8       1.40260         -0.04931
22      3.25781         1.80590
20      4.32051         2.86860
6-      0.00000         -0.93906
18-     0.07618         -0.86288
8-      0.36922         -0.56984
12-     0.71195         -0.22711
16-     0.88517         -0.05389

答案2

根据您之前的问题,我怀疑您有制表符分隔的输入,因此请尝试以下操作:

$ printf '%s\n' "$array" | awk 'BEGIN{FS=OFS="\t"} ($2==0) && c++{s="-"} {$1=$1 s} 1'
2       0.00000 -1.45191
6       0.81778 -0.63413
10      0.85020 -0.60170
8       1.40260 -0.04931
22      3.25781 1.80590
20      4.32051 2.86860
6-      0.00000 -0.93906
18-     0.07618 -0.86288
8-      0.36922 -0.56984
12-     0.71195 -0.22711
16-     0.88517 -0.05389

上面还假设如果0第 2 列中出现第 3 个或后续的值,您仍然希望-在第 1 列中追加 s。

答案3

我们可以用awk以下方法来解决:

printf '%s\n' "$array" |
awk -F '\t' 'BEGIN{OFS=FS}
($2 ~ /^0\.0+$/ && ++k==2),0 {
  $1 = $1 "-"
}1' -
  • 我们使用范围运算符,
  • 范围运算符 最初为 false。当左操作数计算结果为 true 时,范围变为 true 并保持为 true,直到右操作数计算结果为 true。
  • 左操作数是$2 ~ /^0\.0+$/ && ++k==2
  • 因此,当第二列是浮点零并且第二次发生这种情况时,它将评估为真。
  • 之后,范围运算符将保持为 true,直到右侧计算为 true,在我们的例子中为 0,因此永远不会发生。
  • IOW,从第二列为零的行开始到 eof 的范围为 true。
  • 范围内的操作是第一个字段以破折号为后缀。
  • 孤独的1由于我们触及了其中一个字段,因此应通过使用 TAB (OFS) 连接字段来将重构的 $0 打印到 STDOUT。


GNU sed在扩展正则表达式模式( )中使用-E来简化正则表达式的编写:

printf '%s\n' "$array" |
sed -E '
  0,/^[^\t]+\t+0\.0+(\t|$)/b
  //,$s/\t/-&/
' -

  • 正则表达式/^[^\t]+\t+0\.0+(\t|$)/选择第二个字段为零的行。
  • 第一个范围选择从行号零到第二列中第一次出现零的行。所有这些行都未经修改地传递到 STDOUT
  • 下一次,即第二次,在第二列中看到零,直到 eof,在该范围内,我们将第一个空格字符更改为破折号。这预设了行中没有前导空格。
  • 任何其他不属于这两个范围的行都将不加修改地传递到 STDOUT。
  • 第零行号是 GNU sed 扩展,用于处理正则表达式与第一行匹配的情况,就像您的情况一样。

输出:

2   0.00000 -1.45191
6   0.81778 -0.63413
10  0.85020 -0.60170
8   1.40260 -0.04931
22  3.25781 1.80590
20  4.32051 2.86860
6-  0.00000 -0.93906
18- 0.07618 -0.86288
8-  0.36922 -0.56984
12- 0.71195 -0.22711
16- 0.88517 -0.05389

相关内容