我有这个输入
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