Sed условное совпадение и выполнение команды со смещением - PullRequest
1 голос

Я нахожу команду bash для условной замены со смещением.Существующие сообщения, которые я нашел, это условная замена без смещения или фиксированное смещение.

Задача: Если uid содержит 8964, вставьтестрока FORBIDDEN перед DOB.

Каждый файл TXT, представленный ниже, представляет одного пользователя и содержит (в следующем порядке)

  1. некоторое свойство(е)
  2. уникальный uid
  3. какой-то качество (ии)
  4. уникальный DOB
  5. случайный lorem ipsum

Я надеюсь, что смогу преобразовать следующие файлы

# file1.txt (uid doens't match 8964)
admin: false
uid: 123456
happy
movie
DOB: 6543-02-10
lorem ipsum
seo varis lireccuni paccem noba sako

# file2.txt (uid matches 8964)
citizen: true
hasSEAcct: true
uid: 289641
joyful hearty
final debug Juno XYus
magazine
DOB: 1234-05-06
saadi torem lopez dupont

в

# file1.txt (uid doens't match 8964)
admin: false
uid: 123456
happy
movie
DOB: 6543-02-10
lorem ipsum
seo varis lireccuni paccem noba sako

# file2.txt (uid matches 8964)
citizen: true
hasSEAcct: true
uid: 289641
joyful hearty
final debug Juno XYus
magazine
FORBIDDEN
DOB: 1234-05-06
saadi torem lopez dupont

Моя попытка:

Если uid содержит 8964, выполните 2-е совпадение с DOB и вставьте FORBIDDEN выше DOB.

sed '/^uid: [0-9]*8964[0-9]*$/{n;/^DOB: .*$/{iFORBIDDEN}}' file*.txt

Это дает мне непревзойденную { ошибку.

sed: -e expression #1, char 0: unmatched `{'

Я знаю, что sed '/PAT/{n;p}' выполнит {n;p}, если PAT соответствует, но кажется невозможным поместить /PAT2/{iTEXT} внутрь /PAT/{ }.

Как я могу выполнить такую ​​вставку FORBIDDEN?

Ответы [ 3 ]

2 голосов
/ 28 апреля 2019
$ awk '
  /^uid/ && /8964/ {f=1}                     #1
  /^DOB/ && f {print "FORBIDDEN"; f=0}       #2
  1                                          #3
' file
  1. Если строка, начинающаяся с «uid», соответствует «8964», установите флаг
  2. Если строка начинается с «DOB» и установлен флаг, выведите строку и установите флажок
  3. печатать каждую строку
$ awk -v RS='' '/uid: [0-9]*8964/{sub(/DOB/, "FORBIDDEN\nDOB")} 1' file

В качестве альтернативы, обрабатывайте каждый блок, отделенный пустой строкой, как одну запись, а затем вставьте в «FORBIDDEN \ nDOB», если есть совпадение. Я думаю, что первый лучше практиковать. Как правило, когда вы начинаете думать в терминах полей / записей, наступает время для awk / perl.

1 голос
/ 01 мая 2019

попробовал на GNU SED

 sed -Ee '/^uid:\s*\w*8964\w*$/{n;/^DOB:/iFORBIDDEN' -e '}' file*.txt
1 голос
/ 28 апреля 2019

На мой взгляд, это хороший вариант использования для sed.

Вот решение GNU sed с некоторыми пояснениями:

# script.sed
/^uid:.*8964/,/DOB/ { # Search only inside this range, if it exists.
  /DOB/i FORBIDDEN    # Insert FORBIDDEN before the line matching /DOB/.
}

Тестирование:

▶ gsed -f script.sed FILE2 
citizen: true
hasSEAcct: true
uid: 289641
joyful hearty
final debug Juno XYus
magazine
FORBIDDEN
DOB: 1234-05-06
saadi torem lopez dupont
▶ gsed -f script.sed FILE1
admin: false
uid: 123456
happy
movie
DOB: 6543-02-10
lorem ipsum
seo varis lireccuni paccem noba sako

или в одну строку:

▶ gsed -e '/^uid:.*8964/,/DOB/{/DOB/i FORBIDDEN' -e '}' FILE*
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...