我有两个数据文件one.txt
并且two.txt
在Linux系统上。我想将 中 的所有正值转换为负值one.txt
,反之亦然two.txt
,但仅限于第一列。请注意,数据也包含零。
one.txt
是这样的:
10 35.74
8 35.74
6 35.74
4 35.74
2 35.74
0 35.74
two.txt
像这样
-20 35.74
-18 35.74
-16 35.74
-14 35.74
-12 35.74
-0 35.74
我想one.txt
这样改变:
-10 35.74
-8 35.74
-6 35.74
-4 35.74
-2 35.74
-0 35.74
同样,我想将所有负值更改为正值two.txt
我尝试过awk '$1 *= -1' file.txt
,但它搞砸了零。
我需要在两个不同的进程中执行这两个问题。因此,我更喜欢为每个问题使用两个不同的解决方案/代码,而不是在一个步骤中完成
答案1
您的尝试的一个小变体将会起作用:
awk '{ $1 *= -1 } 1' file.txt
问题在于awk '$1 *= -1'
这$1 *= -1
被视为一个条件;应用其效果,但随后将其作为条件,因此仅当结果非零时才输出已处理的行。
添加大括号会导致将乘法应用于所有行,而 本身1
会导致打印所有行。为了避免更改空行,您可以在乘法中添加一个条件:
awk 'NF { $1 *= -1 } 1' file.txt
如果您使用 Gawk1,您可以在更改之前检查第一列是否为数字:
awk 'typeof($1) == "strnum" { $1 *= -1 } 1' file.txt
POSIXLY_CORRECT
1 并且环境中没有变量
答案2
这只是一个文本解析问题。将每行的第一个转换-
为+
:
$ sed 's/-/+/' two.txt
+20 35.74
+18 35.74
+16 35.74
+14 35.74
+12 35.74
+0 35.74
并在每行的第一个数字之前添加一个-
(您的文件似乎有前导空格):
$ sed -E 's/[0-9]/-&/' one.txt
-10 35.74
-8 35.74
-6 35.74
-4 35.74
-2 35.74
-0 35.74
如果您的文件没有问题中显示的前导空格,您可以将其简化为:
sed -E 's/^/-/' one.txt
在所有情况下,您都可以使用-i
就地编辑文件:
sed -i 's/-/+/' two.txt
sed -i -E 's/[0-9]/-&/' one.txt
答案3
负 0 不适用于整数 C 数据类型。当数字没有小数部分时,awk 将其转换为字符串,就像使用printf("%ld")
.
要保留 的符号-0
,您需要类似的东西:
awk '{$1 = sprintf("%g", -$1); print}'
Beware%g
具有 6 位精度,对于大数字将切换到工程符号。%15g
例如,您可以替换为以获得更高的精度。
您可以按文本方式进行操作,而无需在字符串和数字之间来回转换:
perl -pe 's{(-?)(?=\d)}{$1 ? "" : "-"}e'
这还有一个好处是不改变字段之间的间距。您还可以传递一个-i
选项来perl
就地编辑文件(然后需要将其作为参数传递,而不是标准输入)。
答案4
$ awk '!sub(/-/,"",$1){$1="-"$1} 1' one.txt
-10 35.74
-8 35.74
-6 35.74
-4 35.74
-2 35.74
-0 35.74
$ awk '!sub(/-/,"",$1){$1="-"$1} 1' two.txt
20 35.74
18 35.74
16 35.74
14 35.74
12 35.74
0 35.74