Я хочу сократить все числа в файле только до пятого знака после запятой. Например, у меня есть этот файл:
1.0
12.2348604202 0.0000000000 0.0000000000
0.0000000000 3.0320000648 0.0000000000
-1.3752052829 0.0000000000 5.6183021388
Ga O
8 12
Direct
0.590021042 0.500000000 0.794251030
0.409978979 0.500000000 0.205748985
0.909978943 0.000000000 0.205749006
0.090021023 -0.000000000 0.794251030
0.658887031 0.000000000 0.314083014
Итак, я хочу иметь тот же файл, но с числами только с 5 десятичными разрядами.
Если Вы не возражаете против целых чисел, также преобразовываемых в плавающую точку, Вы могли бы использовать numfmt
:
$ numfmt --field=1- --format=%.5f --invalid=ignore < file
1.00000
12.23487 0.00000 0.00000
0.00000 3.03201 0.00000
-1.37521 0.00000 5.61831
Ga O
8.00000 12.00000
Direct
0.59003 0.50000 0.79426
0.40998 0.50000 0.20575
0.90998 0.00000 0.20575
0.09003 0.00000 0.79426
0.65889 0.00000 0.31409
--field=1-
Эта опция говорит numfmt
какие случаи должны быть заменены. 1-
в этом случае означает от первого вхождения до конца строки.
--format=%.5f
Эта опция говорит numfmt
как отформатировать выходные числа. %.5f
в этом случае означает формат их как плавающие числа с 5 десятичными цифрами.
--invalid=ignore
Эта опция говорит numfmt
что сделать в случае, если это не смогло отформатировать число. ignore
в этом случае просто игнорирует проблематичный вход и продолжается со следующим входом.
По умолчанию, numfmt
применяет правила округления IEEE 754 - если Вы хотите простое усечение, можно добавить --round=towards-zero
. Полный список округления опций up
, down
, from-zero
(значение по умолчанию), towards-zero
, nearest
.
Можно просмотреть страницу справочника для получения дополнительной информации:
Если Вы хотите округление IEEE 754, но хотите, чтобы оно применялось строго к числам с плавающей точкой больше чем с 5 цифрами после точки, то я предложил бы использовать perl
- это может соответствовать регулярным выражениям, как sed
, но позволяет Вам применять a sprintf
выражение к полученному шаблону:
perl -pe 's/[+-]?\d*[.]\d{5,}/sprintf "%.5f", $&/ge' file
Как GNU sed
, perl
может изменить файл, оперативный путем добавления -i
опция.
Можно использовать sed
:
sed -E 's/([0-9]+\.[0-9]{5})[0-9]*/\1/g' file
Добавить -i
опция добавить файл на месте.
С GNU awk
:
awk '{print gensub(/([0-9]+\.[0-9]{5})[0-9]*/, "\\1", "g")}' input_file > output_file
Это использует awk
функция gensub
выбрать десятичное число (/([0-9]+\.[0-9]{5})[0-9]*/
) из данного файла (input_file
) и разделение это в две части. Первая часть имеет 5 десятичных разрядов (([0-9]+\.[0-9]{5})
) и вторая часть является остальной частью десятичного числа ([0-9]*
).
gensub
затем заменяет выбранное число его первой частью ("\\1"
) и делает это для всех десятичных чисел, которые это может найти ("g"
) в input_file
.
Команда затем сохраняет результат к выходному файлу (> output_file
).
С GNU sed
:
sed -E 's/\.([0-9]{5})[0-9]*/.\1/g' file
Вывод:
1.0
12.23486 0.00000 0.00000
0.00000 3.03200 0.00000
-1.37520 0.00000 5.61830
Ga O
8 12
Direct
0.59002 0.50000 0.79425
0.40997 0.50000 0.20574
0.90997 0.00000 0.20574
0.09002 -0.00000 0.79425
0.65888 0.00000 0.31408
Используйте расширенные регулярные выражения с -E
:
sed -E
Соответствуйте шаблону .<five digits><n digits>
с \.([0-9]{5})[0-9]*
. Получите эти 5 цифр после точки .
с ([0-9]{5})
s/\.([0-9]{5})[0-9]*/
Замените соответствие точкой .
и полученный шаблон:
/.\1/