Замена захваченной группы с помощью SED

xxxxxx15 | xxxxxx02 | RM99999 | xxxxx | Ankur | xxxxx | xxxxxxxx | M | xxxxxxxx | | | | Ххххххй | ххй | XXXXXXXX | | 10 | Нью-Йорк | 23,00 | F | P | | | Н.А.

Хотите заменить 10 на 65, у меня есть шкаф sed -i '/^.\{20\}RM99999/ s/^\(?:[^|]*\|\)\{16\}\([^|]*\)/\165/' test.txt

Но он заменяет первый символ с 65 ( RM99999 может быть в других местах, но нужно заменить линию, которая имеет RM99999 на 20-м RM99999 )

выглядит как проблема XY.

почему бы не попробовать с awk?

 awk -F\| -v OFS=\| '$3=="RM99999" && $17 == 10 { $17=65 } {print ; } ' 

где

  • -F\| сказать awk для использования | как разделитель полей ( \ tell shell для выхода | )
  • -v OFS=\| сказать awk для использования | как разделитель полей при выходе записей
  • $3=="RM99999" && $17 == 10 выберите строку с третьей поданной как RM99999 и семнадцатый как 10
  • $17 = 65 заменить на 65
  • { print ; } { print ; } распечатать весь шаблон, изменить и не изменять
 sed '/^.\{19\}RM99999/s/10/65/' <in >out 

Поменяет первое вхождение строки 10 на строку 65 на строку, где строка RM99999 начинается с 20-го символа.

Думаю, некоторые считают, что 17-е поле должно быть заменено. Я действительно не понимаю, почему, потому что я не вижу этого в вопросе, но если это то, что вы хотите …

 sed '/^.\{19\}RM99999/s/[^|]*/65/17' <in >out 

… что заменит 17-й | поле с строкой 65 на строке, где строка RM99999 начинается с 20-го символа.

Я вроде как хватаюсь за соломинку, но, может быть, они означают только 10 и только в 17-м поле, и только на линиях, где RM99999 запускает 20 символов? Это немного сложнее …

 sed -e'/^.\{19\}RM99999/s/|/|\n/16' \ -e's/\n\([^|]*\)10/\165/;s/\n//' <in >out 

… но это сделает. Подумайте об этом, он выглядит немного больше, как ваш собственный код. Может быть, это то, что нужно в конце концов.

Это немного более прямо …

 sed -e'/^.\{19\}RM99999/!b' \ -e's/|\([^|]*10\)*/&\n/16' \ -e's/10\n/65/;s/\n//' 

И это делает это за один раз – если количество полей фиксировано, то есть.

 sed -e'/^.\{19\}RM99999/s/10\([^|]*\(|[^|]*\)\{7\}\)$/65\1/' 

Вы можете сделать то же самое с передней стороны, конечно …

 sed -e'/^.\{19\}RM99999/s/^\([^|]*\(|[^|]*\)\{16\}\)10/\165/' 

Но поскольку на хвосте имеется как минимум половина полей, вероятно, лучше не делать этого, если ему это поможет.

И немного проще написать синтаксис Extended regexp:

 sed -Ee'/^.{19}RM99999/s/10([^|]*(\|[^|]*){7})$/65\1/'