Прежде чем поднять флаг, я попробовал несколько вещей, но не получил желаемого результата.
У меня есть много текстовых файлов, к которым я хочу добавить собственную нумерацию;
the first 2 lines should be prefixed 00A: , 00B:
and remaining lines should be incremental, like 001: ,002: ,003: , and so on
В настоящее время я использую эту команду для возрастающей нумерации.
awk '{printf("%03d: %s\r\n", NR,$0)}' file1.txt > file2.txt
*который делает дополнительные номера. ок для всего файла; но не несколько необходимых типов.
Пример входного файла:
136725A6449C5279 933FB466C9CD699B
8FFBBA87E9D3209A AB41FBDC5E281A92
FF80DA7B0054FB29 006BF1C82C75C341
FA118264221B02A7 81E9A1FEB75FFB3D
31AA9FC566C3ADE0 70DDFD6DED2BF29C
F0B39014DA7FA6B1 77401108A81E33E1
74EF54060BC2B72F B5518D896DDC266F
DE10C97F9FBDA5A6 6C79566CA1BDC06E
Желаемый результат:
00A: 136725A6449C5279 933FB466C9CD699B
00B: 8FFBBA87E9D3209A AB41FBDC5E281A92
001: FA118264221B02A7 81E9A1FEB75FFB3D
002: 31AA9FC566C3ADE0 70DDFD6DED2BF29C
003: F0B39014DA7FA6B1 77401108A81E33E1
004: 74EF54060BC2B72F B5518D896DDC266F
005: DE10C97F9FBDA5A6 6C79566CA1BDC06E
Ни Awk, ни sed
не делают этого хорошо, но в Perl это встроено.
perl -pe 'BEGIN { $prefix = "A"; }
$prefix = "1" if ($. == 3);
printf "%03s: ", $prefix++;' file
Важнейшей особенностью здесь является то, что в Perl "A"++
производит "B"
изначально. Однако с ведущими нулями это работает не так хорошо; поэтому я прибегнул к дополнению здесь.
Ваш вопрос довольно неясен относительно того, что должно произойти после 00Z
или после 009
, поэтому мне пришлось гадать. В Perl "Z"++
есть "AA"
.
Если вы действительно настаиваете на решении Awk, это можно сделать примерно так:
awk '{ printf("%03s: %s\n", (NR == 1 ? "A" : \
(NR == 2 ? "B" : NR-2)), $0)}' file
Я вынул фугли \r
; если вы используете Windows, возможно, верните его обратно (или рассмотрите свои варианты).
Как отмечено в комментариях, это работает на MacOS / nawk
, но может не работать на других Awk.
кстати, я использовал предложенную команду awk; Perl - это не то, с чем я знаком
Perl — это совершенно другой язык, но у него есть некоторые конструктивные особенности, которые делают его подмножество довольно знакомым пользователям Awk или sed
. В наши дни я ожидаю, что он будет установлен почти везде, возможно, за исключением урезанных образов Docker или встроенных систем. Но достаточно справедливо; После многих лет работы на Perl я обнаружил, что предпочитаю Awk для небольших задач и Python для более крупных задач.
Какой awk вы используете? %03s
кажется, не работает на моем gawk и mawk, только на nawk (оригинальном awk).
Я тестировал это на MacOS, думаю, это означает «One True Awk».
@tripleee Любопытно, это awk 'BEGIN{print 1 == 2 ? 3 : 4}'
все еще не работает на вашем awk?
@AndreWildberg Да, после 1
появляется синтаксическая ошибка
@tripleee Спасибо, Mac все еще использует старую базу nawk/oawk, а не gawk и mawk, которые в настоящее время имеют больше общего.
я использую macOS 11
%03
дополняет только ведущие нули для чисел, а не для строк, поэтому не ждите, что %03s
дополнит 0.
@AndreWildberg всегда заключайте в скобки ваши троичные выражения для ясности, и это также касается этой конкретной проблемы (по крайней мере, о которой довольно часто сообщается в MacOS), то есть используйте awk 'BEGIN{print (1 == 2 ? 3 : 4)}'
Что касается «Ни Awk, ни sed не делают этого очень хорошо» — согласен с sed, но я бы сказал, что awk делает это довольно хорошо.
@EdMorton Обычно так и есть. Просто воспринял это как тест, чтобы узнать состояние Mac awk. Но, возможно, вы захотите добавить это к своему ответу unix.stackexchange.com/questions/699842/… ;)
@EdMorton Я имею в виду общий случай «приращения» строки. Все решения здесь отлично работают от A до Z, но отсюда не очень хорошо обобщаются.
Вы имеете в виду, например, заставить "Z"++
стать "AA"
? Да, вам придется реализовать небольшой цикл, чтобы сделать это в awk, так как в awk выполнение любой арифметической операции с использованием строки сначала преобразует строку в число, а затем результатом является число, и попытка пре-/пост-инкремента приведет к увеличению буквальной строки. быть синтаксической ошибкой, точно так же, как попытка увеличить буквальное число до/после.
С любым POSIX awk
:
awk '{s = NR>2 ? sprintf("%03d",NR-2) : "00" substr("AB",NR,1); print s ": " $0}'
спасибо, а предыдущий у меня работал; ваше решение также сработало.
Я бы использовал GNU AWK
для этой задачи следующим образом: пусть file.txt
контент будет
Able
Baker
Charlie
Dog
затем
awk -v prefixes = "00A 00B" 'BEGIN{split(prefixes,arr)}{prefix=(NR in arr)?arr[NR]:sprintf("%03d",++i);print prefix ": " $0}' file.txt
дает результат
00A: Able
00B: Baker
001: Charlie
002: Dog
Объяснение: я устанавливаю переменную prefixes в список префиксов с разделением пробелов, затем в начале заполняю массив arr
в контексте. Для каждой строки я проверяю, есть ли в массиве префикс для данной строки, если да, то я использую их, в противном случае я использую sprintf
для создания префикса из предварительно увеличенной переменной i
, затем печатаю конкатенацию префикса, желаемого разделителя и заданной строки. Это решение автоматически адаптируется к любому количеству префиксов, например. если вы хотите 00A 00B 00C, то достаточно установить префиксы 00A 00B 00C
.
(проверено в GNU Awk 5.1.0)
Используя любой awk:
$ awk -v OFS=': ' '{print ( NR<3 ? sprintf("00%c",NR+64) : sprintf("%03d",NR-2) ), $0}' file
00A: 136725A6449C5279 933FB466C9CD699B
00B: 8FFBBA87E9D3209A AB41FBDC5E281A92
001: FF80DA7B0054FB29 006BF1C82C75C341
002: FA118264221B02A7 81E9A1FEB75FFB3D
003: 31AA9FC566C3ADE0 70DDFD6DED2BF29C
004: F0B39014DA7FA6B1 77401108A81E33E1
005: 74EF54060BC2B72F B5518D896DDC266F
006: DE10C97F9FBDA5A6 6C79566CA1BDC06E
огромное спасибо, это сработало так прекрасно. именно то, что я искал; еще раз спасибо.