Форматирование чисел в определенном столбце файла на месте

На первый взгляд мне показалось, что на это нельзя ответить, кроме как сказать: нет, варианты, которые кажутся бессмысленными, всегда можно найти. Вы можете создать свою собственную программу, которая преднамеренно имеет опции с совершенно бессмысленными названиями. (Конечно, даже тогда вы могли бы сказать, что они значимы в своей бессмысленности, если бы они были намеренно выбраны бессмысленными.)

При дальнейшем рассмотрении, однако, я понял, что двусмысленность в том, что означает семантика параметра, на самом деле является важной и полезной частью того, как командные -параметры строки называются и curl -Iявляется особенно показательным примером этого.

Как говорит муру , варианты не должны быть семантическими. Но curlвариант -Iявляется семантическим. Из завиток (1):

-i/--include
        (HTTP) Include the HTTP-header in the output. The HTTP-header includes things like server-name, date of the document, HTTP-version and more...

-I/--head
       (HTTP/FTP/FILE) Fetch the HTTP-header only! HTTP-servers feature the command HEAD which this uses to get nothing but the header of a document. When used on a FTP or FILE file, curl displays the file size and last modification time only.

-i— это краткая форма --include, что приводит к включению заголовка HTTP. Хотя -Iявляется краткой формой --head, семантически это более сильная форма -i, поскольку -iдает вам заголовок HTTP, -Iдает вам только заголовок HTTP.

Это дает представление о вашем более широком вопросе :существует множество различных критериев, по которым можно судить о том, является ли имя параметра семантическим.Когда параметр является семантическим , он может быть преднамеренным или непреднамеренным. Если вас интересует только то, существует ли какой-либо способ запомнить параметр как семантический, тогда да, вы всегда можете придумать причину, по которой имя связано с его значением.

Некоторые опции являются семантическими более чем одним способом. Вы можете заставить GNUgrepотображать строки, смежные с соответствующими строками, с помощью -Aдля после , -Bдля до и -Cдля контекста . что дает вам обоим. Таким образом, краткие формы трех вариантов -A/--after-context, -B/--before-contextи -C/--context, очень близкие друг другу по смыслу, также близки друг другу по смыслу. алфавит. Это семантика?

Чтобы продолжить это и получить точный ответ, вы можете выполнить поиск применимых стандартов, таких как POSIX.1 -2008 . Кажется крайне неправдоподобным, что он запрещает бессмысленно названные опции, но я полагаю, что вам нужно внимательно прочитать все это, чтобы быть уверенным. Беглый поиск не выявляет требования, чтобы опции что-либо значили. В частности, эти официальные рекомендации--требуются только для команд, чья документация заявляет о соответствии им --рекомендуются различные ограничения на то, как могут быть названы опции и эффект от их передачи, но они не упоминают ничего, что могло бы следует интерпретировать как требование или рекомендацию о том, что имена опций имеют смысл. Даже если вы что-то нашли, многие Unix -подобные системы не стремятся к полному соответствию POSIX...

Но весь этот ход мыслей --обращения к официальным источникам, чтобы определить, (поставщики должны притворяться, что )название каждой опции что-то означает --, довольно глупо. Самое полезное, что нужно знать об опциях, это то, что их имена могут относиться друг к другу множеством способов. Они могут быть названы по словам, по другим вариантам,или для алфавитной близости к другим вариантам. Иногда это просто буква (или цифра ), которые оказались доступны. Размышление об этих способах может помочь вам запомнить параметры, найти параметры при поиске на справочных страницах и принять правильное решение о том, какие имена параметров должны использоваться вашими собственными сценариями или программами.

И последнее замечание: полезно иметь в виду, что не только краткие -формы опции могут быть названы таким образом, что это не позволит вам сделать вывод об их значении. Например, параметры длинной формы -от --regexи от --regexpдоmlocateназываются семантически в том смысле, что они оба имеют отношение к регулярным выражениям. Но в их названии нет ничего, что говорило бы вам о том, что --regexpозначает, что следующий аргумент является BRE , а --regexозначает все аргументы шаблона. являются ЭРЭ с.

0
05.09.2020, 12:31
4 ответа

у вас есть ошибка в коде awk, вы сначала печатаете измененное значение $4 плюс полную строку

Правильный вариант такой:awk -F"|" 'NR<=1{print $0;next} {{printf($1"|" $2"|"$3"|%.2f|"$5"|"$6"\n",$4)}}' test

$ awk -F"|" 'NR<=1{print $0;next}  {{printf($1"|" $2"|"$3"|%.2f|"$5"|"$6"\n",$4)}}' test
bank|Branch|Comment|Amount|Extra1|Extra2
xyz|we||100,00||
xyz|we||100,00||
xyz|we|paid for inv# 34VM23-SEP-20|23459900,00||
xyz|errt||-230,00||
xyz|ss||234,00||
xyz|we|valid|990,00||
xyz|we|9922.9 paid|9922,00||
xyz|we||0,00||
xyz|we||0,00||
xyz|we||0,00||

вам нужно напечатать все поля нетронутыми плюс поле 4, измененное по вашему желанию. Чтобы не обрабатывать первую строку, вы проверяете NR и просто печатаете строку без изменений и продолжаете с nextдо второй строки

отредактировать у меня может быть проблема с моей версией awk, потому что исходная команда и моя версия не сохраняют десятичные числа, если они есть, и устанавливаю их в 0. Я думаю, это должно работать для вас. Что-то, связанное с моими МЕСТНЫМИ, я думаю. например 234.78превращается в 234,00на моей машине.

Еще одно решение из комментарияPaul _Pedantсостоит в том, чтобы изменить значение $4 напрямую и вывести после:

plonky@sd-143012:~/work$ awk -F '|' '{ {OFS=FS} if (FNR > 1) $4 = sprintf ("%.2f", $4); print; }'  test
bank|Branch|Comment|Amount|Extra1|Extra2
xyz|we||100,00||
xyz|we||100,00||
xyz|we|paid for inv# 34VM23-SEP-20|23459900,00||
xyz|errt||-230,00||
xyz|ss||234,00||
xyz|we|valid|990,00||
xyz|we|9922.9 paid|9922,00||
xyz|we||0,00||
xyz|we||0,00||
xyz|we||0,00||
1
18.03.2021, 23:07

Примерно так должно работать:

awk -F '|' 'FNR>1 {printf "%s|%s|%s|%.2f|%s|%s\n", $1,$2,$3,$4,$5,$6}'

-F '|'у вас уже есть, но это разделитель полей.

Вы сказали, что хотите пропустить первую строку, это можно сделать с помощью FNR>1. FNR— номер входной записи в текущем входном файле. Поскольку awk является построчным считывателем, >1произносит процесс после первой строки .

Использование printfтакже правильно, но ваш синтаксис не соответствует желаемому результату. Вы можете расширить, чтобы напечатать всю строку по запросу.

Вы также забыли возврат строки \nв конце строки,вот почему у вас странная планировка.

1
18.03.2021, 23:07

с использованием Раку (урожденная Perl6)

Я бы, вероятно, сделал что-то чрезвычайно механическое, используя Raku, с явными вызовами splitи join. Таким образом, вы можете перейти на другой разделитель столбцов (, например. запятая )с использованием той же цифры -код форматирования:

~$ raku -e 'for lines.skip(1) {my @a =.split("|");.subst(@a[3], sprintf( "%.2f", @a[3] )).join("|").put };'

Кроме того, я написал код для создания файла tmp, который сначала содержит заголовок, а затем добавляет отформатированные строки данных. Не то, что вы просили --, но это работает. Кроме того, с этим кодом нет необходимости знать общее количество столбцов в строке (за пределами столбца, который вы пытаетесь отформатировать ).

Собираем все воедино:

~$ raku -e '.say for lines[0];' < bank.txt > tmp
~$ raku -e 'for lines.skip(1) {my @a =.split("|");.subst(@a[3], sprintf( "%.2f", @a[3] )).join("|").put };' < bank.txt >> tmp

Выход:

Bank|Branch|Comment|Amount|Extra1|Extra2
xyz|we||100.00||
xyz|we||100.10||
xyz|we|paid for inv# 34VM23-SEP-20|23459900.00||
xyz|errt||-230.00||
xyz|ss||234.78||
xyz|we|valid|990.20||
xyz|we|9922.90 paid|9922.9||
xyz|we||0.90||
xyz|we||0.00||
xyz|we||0.00||

ХТН.

https://raku.org/

0
18.03.2021, 23:07

С Миллером

mlr --csvlite --fs '|' put '$Amount = fmtnum($Amount,"%.2f")' file

Чтобы изменить файл на месте, добавьте переключатель командной строки -I.

0
18.03.2021, 23:07

Теги

Похожие вопросы