Добавление символа в n-й позиции соответствующей строки

Мне нужно найти команду sed / awk, которая будет вставлять символ в n-ое положение соответствующей строки HAVING LENGTH 10. Например, мне нужно найти строку, начинающуюся с шаблона 541 и имеющую длину 10, затем вставить 9 в 5-ю позицию этой строки без замены, в результате получается 11-символьная строка.

Строки – это слова, разделенные пробелом. Также шаблон всегда будет в начале слова, но может быть несколько совпадений в каждой строке.

Входной файл:

 5414444444 87654873234 88888888888 6646666666 54122222222 54155555558888 54176543235 5416666666 

Выходной файл:

 54149444444 87654873234 88888888888 6646666666 54122222222 54155555558888 54176543235 54169666666 

Как видно из примера, OP означает word не string поэтому

 sed 's/\b541./&9/g' file 

Если 541 может начинаться с другого места в слове (не с самого начала)

 sed 's/\b\S*541/\n&/g #mark a beginning of word(s) with pattern s/\n\(....\)/\19/g #remove mark and do adding ' file 

Вы можете ограничить количество символов словом (-ами) следующим образом

 sed 's/\b\(541.\)\(\S\{6\}\)\b/\19\2/g' file 

или более общий

 sed 's/\b541./&\n/g;s/\n\S\{6\}\b/9&/g;s/\n//g' file 

Вы можете использовать perl

 perl -lane 'map{length==10&&/^541/&&s/.{4}/$&9/}@F;print join(" ",@F)' file 

Используйте карту для выполнения проверок и подписок для каждого поля. Затем печатает массив полей, присоединяющихся к одному пространству (так что испортит форматирование, если не согласованные отдельные пробелы между полями)

или просто используя регулярное выражение

 perl -lane 'map{s/^541.\K.{6}$/9$&/}@F;print join(" ",@F)' file 

Вывод:

 54149444444 87654873234 88888888888 6646666666 54122222222 54155555558888 54176543235 54169666666 

Портабельно:

 sed ' s/.*/ & /; # add a leading and trailing space :1 s/\([[:blank:]]541[^[:blank:]]\{2\}\)\([^[:blank:]]\{5\}[[:blank:]]\)/\19\2/g # replace in a loop until there is no more match t1 # remove the blanks we added earlier: s/^ //;s/ $//' 

Вы можете избежать временного добавления верхнего и конечного пробелов, ища вхождение этой 10 непустой строки в начале или в конце списка в дополнение к следующему / перед пробелом. Это можно сделать POSIXly с одним регулярным выражением, но это немного громоздко:

 sed ' :1 s/^\(\(.*[[:blank:]]\)\{0,1\}541[^[:blank:]]\{2\}\)\([^[:blank:]]\{5\}\([[:blank:]].*\)\{0,1\}\)$/\19\3/ t1' 

С perl , используя операторы look-around:

 perl -lpe 's/((?<!\H)541\H\H)(\H{5})(?!\H)/${1}9$2/g' 

Или обрабатывать слова один за другим:

 perl -lpe 's{\H+}{$&=~s/^541..\K.{5}$/9$&/r}ge' 

( \K и флаг замены r требуют относительно недавней версии perl ).