Как я могу использовать SED или AWK для замены заполнителей в файле шаблона переменным содержимым, содержащим специальные символы?

8

CentOS 6.3

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

Файл шаблона содержит следующее:

Alert Report

Alert has triggered at TMPDATE

HEADERS
-------
TMPHEADERS

SOURCE IP
---------
TMPSOURCEIP

Я хочу, чтобы мой сценарий нашел и заменил заполнители «TMP» актуальной информацией, относящейся к предупреждению.

IP-переменные даты и источника, кажется, работают нормально, но если / когда я пытаюсь найти / заменить TMPHEADERS, это вызывает странные симптомы, включая весь вывод, чтобы быть пустым. Я вполне уверен, что это связано с заголовками, содержащими много специальных символов (@% и т. Д.).

Кто-нибудь может посоветовать, пожалуйста, как лучше всего это сделать с помощью bash?

Мой текущий код выглядит так:

cat /test/emailtemplate | sed s/TMPHEADERS/"$HEADERS"/ > /test/output

ОБНОВИТЬ

Согласно запросу, вот пример набора заголовков, которые я пытаюсь вставить в файл шаблона (IP-адреса и адрес электронной почты были изменены, чтобы защитить невинных :-)):

From foo@yahoo.com Thu Apr 25 20:18:19 2013
Return-Path: <foo@yahoo.com>
Received: from nm30-vm0.bullet.mail.ne1.yahoo.com (nm30-vm0.bullet.mail.ne1.yahoo.com [98.138.11.36])
by serv.example.com (8.14.4/8.14.4) with ESMTP id r3Q3IJVV009411
for <test@example.com>; Thu, 25 Apr 2013 20:18:19 -0700
Received: from [108.108.108.108] by nm30.bullet.mail.ne1.yahoo.com with NNFMP; 26 Apr 2013 03:18:19 -0000
Received: from [98.138.87.11] by tm15.bullet.mail.ne1.yahoo.com with NNFMP; 26 Apr 2013 03:18:17 -0000
Received: from [127.0.0.1] by omp1001.mail.ne1.yahoo.com with NNFMP; 26 Apr 2013 03:18:17 -0000
X-Yahoo-Newman-Property: ymail-3
X-Yahoo-Newman-Id: 92334348.43667.bm@omp10122422401.mail.ne1.yahoo.com
Received: (qmail 29701 invoked by uid 65501); 26 Apr 2013 03:18:17 -0000
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s1024; t=1366946297; bh=yjMzVONHAyJxQob7tLNdIN2RpfGHWVw1Kb5Qr+enYF8=; h=X-YMail-OSG:Received:X-Rocket-MIMEInfo:X-Mailer:Message-ID:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type; b=CQGilBx8NertE4j75dsfsdfs+IKRzIx5vlH5YdzqFLd4ThfEyMs11sdfsdfsdXsAH1yteACnwSER+QXJQ80BfLGbJnIWm+29I8A4geOPIHGKoOUCnPaD+/0bHfAps0JIcwEju8Tcvg4VDVWw=
DomainKey-Signature:a=rsa-sha1; q=dns; c=nofws;
s=s1024; d=yahoo.com;
h=X-YMail-OSG:Received:X-Rocket-MIMEInfo:X-Mailer:Message-ID:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type;
b=5TIRL55VM2J2lPLsX9iCE4sdlkfjlEM2245M6qzg1oGrnZd61ykL4xQSsc3cYNz95fwNy67aRRC89n6xcti28ee5rjmlK0MDIskSB5sKlv165mNjmzF1LNx6uFXalI8QGSwiQt2uWLYvI7RrTVeZFELDfFVZyqygEl5k=;
X-YMail-OSG: EDT4ym4VM1lVQMdtAQ5zqfE59jR1Mtip4vVL1fBzNxFdGvA
YjAJ3MXC1EusloknrsPx3drxzR1b4PFErK.UhdgWePhK7TTCHhhju4XP4i7x
76WASceqp77T5itvZmilv5UuICJw3BCEd0fdADctfBYhLNwoALxjp6cnJMmE
Z4dYVtlp5vUFqg1pHxqGOXqrtjeZffM4dMftnn.Q8LlVEkj3pZ6ZJV_kKFtj
vGEGS5PAW0tIHWPEqVERYzmDOfF5sVSQLayPi6EM_i1OE038434laijEWbH0
nZt1Vkg3syO0t1BaTLN4B1bXeS8cv3GlbLO4ot7zVwA3sH4UhsC5M6xiWNFU
3iroObJ5BObL99VO3ktvC4KzekAWJ_fE85TQJhQKj6Iolgb4xlWa2x414xuA
awO4pJI9grDjycUcmhmKwLZEt_.0OBLfSi5MSviaiCNMuU5qIdHm7VCGdORP
Mc68rDkpmJE9I9Z.QZfhH5cFxqqmpyIOMTs0iIBGYz5d9QHMWCuo-
Received: from [102.102.102.102] by web12341105.mail.ne1.yahoo.com via HTTP; Thu, 25 Apr 2013 20:18:17 PDT
X-Rocket-MIMEInfo: 002.001,VGVzdGluZyAxMjMgTGEgbGEgbGEBMAEBAQE-
X-Mailer: YahooMailWebService/0.8.141.536
Message-ID: <136634397.44849.YahooMailNeo@web126205.mail.ne1.yahoo.com>
Date: Thu, 25 Apr 2013 20:18:17 -0700 (PDT)
From: Test Account <foo@yahoo.com>
Reply-To: Test Account <foo@yahoo.com>
Subject: Test
To: "test@example.com" <test@example.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="102743210-1541163991-1366946297=:49149"
Майк Б
источник
2
Простые инструменты для работы с текстом имеют ограничения, они подходят только для базовой обработки шаблонов. Лучше см. Инструмент для создания текстовых файлов из шаблона . Имеет ссылки на похожие вопросы по Stack Exchange и Server Fault , смотрите их тоже.
manatwork
Не могли бы вы привести несколько примеров неудачных заголовков?
Terdon
@terdon Абсолютно. Я обновил вопрос, добавив несколько примеров заголовков (с разными ips и адресами электронной почты).
Майк Б

Ответы:

7

Это сложно в sed, потому что в sed s/TMPHEADERS/"$HEADERS"/, значение переменной подставляется оболочкой до того, как команда достигает sed, поэтому такие символы, как &\/в этом, $HEADERSимеют особое значение в тексте замены. Sed не имеет возможности поиска переменной.

Эта задача довольно проста с awk. Передайте HEADERSпеременную в среде:

export HEADERS
</test/emailtemplate awk '
    {gsub(/^TMPHEADERS$/, environ["HEADERS"]); print}
' > /test/output

или как переменная awk:

</test/emailtemplate awk -v HEADERS="$HEADERS" '
    {gsub(/^TMPHEADERS$/, HEADERS); print}
' > /test/output
Жиль "ТАК - перестань быть злым"
источник
3

Есть несколько возможностей:

sed Вы должны будете избегать каждого символа в $ HEADERS, чтобы сделать вызов sed безопасным.

HEADERS_ESCAPED="$(echo "$HEADERS" | sed -n 's/./\\&/gp')"
# double-useless use of cat BTW
sed "s/TMPHEADERS/$HEADERS_ESCAPED/" /test/emailtemplate > /test/output

Кстати: нет абсолютно никакой причины вызывать sed один раз для каждого изменения:

sed -n -e s/X/"$X"/ -e s/Y/"$Y" -e s/Z/"$Z"/ -e p inputfile > outputfile

сам по себе

while IFS= read -r line; do
  line="${line/TMPDATE/"$TMPDATE"}"
  # ...
  line="${line/TMPHEADERS/"$HEADERS"}"
  printf '%s\n' "$line"
done <inputfile >outputfile
Хауке Лагинг
источник
@terdon Действительно, это была неправильная переменная. sed ничего не расширяет (из-за экранирования каждого символа в переменной). Что вы имеете в виду? Вы пробовали это, не работает?
Хауке Лагинг
Плохо, я всегда цитирую свои sedкоманды (я думал, что это было необходимо), и переменные bash не раскрываются (я имею в виду, что 's / foo / $ bar /' фактически печатается, $barа не содержимое переменной). Ваша команда работала нормально без кавычек (как вы их опубликовали), она провалилась, когда я поместил ее в одинарные кавычки. Извините, сила привычки, не стесняйтесь откатить мою правку.
Terdon
Спасибо за оперативную помощь, но я получаю сообщение об ошибке: sed: -e expression #1, char 121: unterminated s 'command` Я полагаю, что я неправильно настроил команду: sed "s/TMPHEADERS/$HEADERS_ESCAPED/" /home/foo/scripts/fooalert/emailtemplate > /home/foo/scripts/fooalert/testing1234 я подтвердил, что теперь все заголовки экранированы правильно.
Майк Б
@MikeB Можете ли вы узнать, какой символ вызывает проблему? Я не уверен, возможно ли иметь новую строку в тексте замены. Возможно ли, что $ HEADERS_ESCAPED содержит новую строку?
Hauke ​​Laging
1

Я не уверен, что понимаю, что вы хотите сделать. Если вы хотите, например, заменить строку TMPHEADERSдлинным списком размещенной вами информации заголовка, это решение Perl может сделать это:

perl -e 'open(A,"header"); ## open the header file
         $h=join("",<A>); ## save its contents in a string
         while(<>){ ## go through the input file
            s/TMPHEADERS/$h/; ## replace
            print        ## print each line
         }' template 

Файл templateявляется шаблоном вашего вопроса, и в нем headerесть строки заголовка, которые вы разместили. Результат

Alert Report

Alert has triggered at TMPDATE

HEADERS
-------
From foo@yahoo.com Thu Apr 25 20:18:19 2013
Return-Path: <foo@yahoo.com>
Received: from nm30-vm0.bullet.mail.ne1.yahoo.com (nm30-vm0.bullet.mail.ne1.yahoo.com [98.138.11.36])
by serv.example.com (8.14.4/8.14.4) with ESMTP id r3Q3IJVV009411
for <test@example.com>; Thu, 25 Apr 2013 20:18:19 -0700
Received: from [108.108.108.108] by nm30.bullet.mail.ne1.yahoo.com with NNFMP; 26 Apr 2013 03:18:19 -0000
Received: from [98.138.87.11] by tm15.bullet.mail.ne1.yahoo.com with NNFMP; 26 Apr 2013 03:18:17 -0000
Received: from [127.0.0.1] by omp1001.mail.ne1.yahoo.com with NNFMP; 26 Apr 2013 03:18:17 -0000
X-Yahoo-Newman-Property: ymail-3
X-Yahoo-Newman-Id: 92334348.43667.bm@omp10122422401.mail.ne1.yahoo.com
Received: (qmail 29701 invoked by uid 65501); 26 Apr 2013 03:18:17 -0000
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s1024; t=1366946297; bh=yjMzVONHAyJxQob7tLNdIN2RpfGHWVw1Kb5Qr+enYF8=; h=X-YMail-OSG:Received:X-Rocket-MIMEInfo:X-Mailer:Message-ID:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type; b=CQGilBx8NertE4j75dsfsdfs+IKRzIx5vlH5YdzqFLd4ThfEyMs11sdfsdfsdXsAH1yteACnwSER+QXJQ80BfLGbJnIWm+29I8A4geOPIHGKoOUCnPaD+/0bHfAps0JIcwEju8Tcvg4VDVWw=
DomainKey-Signature:a=rsa-sha1; q=dns; c=nofws;
s=s1024; d=yahoo.com;
h=X-YMail-OSG:Received:X-Rocket-MIMEInfo:X-Mailer:Message-ID:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type;
b=5TIRL55VM2J2lPLsX9iCE4sdlkfjlEM2245M6qzg1oGrnZd61ykL4xQSsc3cYNz95fwNy67aRRC89n6xcti28ee5rjmlK0MDIskSB5sKlv165mNjmzF1LNx6uFXalI8QGSwiQt2uWLYvI7RrTVeZFELDfFVZyqygEl5k=;
X-YMail-OSG: EDT4ym4VM1lVQMdtAQ5zqfE59jR1Mtip4vVL1fBzNxFdGvA
YjAJ3MXC1EusloknrsPx3drxzR1b4PFErK.UhdgWePhK7TTCHhhju4XP4i7x
76WASceqp77T5itvZmilv5UuICJw3BCEd0fdADctfBYhLNwoALxjp6cnJMmE
Z4dYVtlp5vUFqg1pHxqGOXqrtjeZffM4dMftnn.Q8LlVEkj3pZ6ZJV_kKFtj
vGEGS5PAW0tIHWPEqVERYzmDOfF5sVSQLayPi6EM_i1OE038434laijEWbH0
nZt1Vkg3syO0t1BaTLN4B1bXeS8cv3GlbLO4ot7zVwA3sH4UhsC5M6xiWNFU
3iroObJ5BObL99VO3ktvC4KzekAWJ_fE85TQJhQKj6Iolgb4xlWa2x414xuA
awO4pJI9grDjycUcmhmKwLZEt_.0OBLfSi5MSviaiCNMuU5qIdHm7VCGdORP
Mc68rDkpmJE9I9Z.QZfhH5cFxqqmpyIOMTs0iIBGYz5d9QHMWCuo-
Received: from [102.102.102.102] by web12341105.mail.ne1.yahoo.com via HTTP; Thu, 25 Apr 2013 20:18:17 PDT
X-Rocket-MIMEInfo: 002.001,VGVzdGluZyAxMjMgTGEgbGEgbGEBMAEBAQE-
X-Mailer: YahooMailWebService/0.8.141.536
Message-ID: <136634397.44849.YahooMailNeo@web126205.mail.ne1.yahoo.com>
Date: Thu, 25 Apr 2013 20:18:17 -0700 (PDT)
From: Test Account <foo@yahoo.com>
Reply-To: Test Account <foo@yahoo.com>
Subject: Test
To: "test@example.com" <test@example.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="102743210-1541163991-1366946297=:49149"


SOURCE IP
---------
TMPSOURCEIP

Вы можете расширить это для двух наборов заголовков следующим образом:

perl -e 'open(A,"header1");
         $h1=join("",<A>);
         open(B,"header2");
         $h2=join("",<B>);
         while(<>){
            s/TMPHEADERS/$h1/;
            s/TMPSOURCEIP/$h2/;
            print        
         }' template 
Тердон
источник
Я уважаю этот ответ, но, к сожалению, я не знаю Perl достаточно хорошо, чтобы поддерживать его на постоянной основе. Я понимаю, что это не очень хороший ответ (или причина не использовать более эффективный код). Спасибо.
Майк Б
1

Использование m4макропроцессора для замены TMPSOURCEIPи тем, TMPDATEчто определено в командной строке, и тем, TMPHEADERSчто находится в файле headers.txt. Шаблон находится в template.txt.

$ m4 -DTMPDATE="$(date)" -DTMPSOURCEIP="1.1.1.1" -DTMPHEADERS='include(headers.txt)' template.txt
Alert Report

Alert has triggered at Mon Sep 25 18:46:34 CEST 2017

HEADERS
-------
From foo@yahoo.com Thu Apr 25 20:18:19 2013
Return-Path: <foo@yahoo.com>
Received: from nm30-vm0.bullet.mail.ne1.yahoo.com (nm30-vm0.bullet.mail.ne1.yahoo.com [98.138.11.36])
by serv.example.com (8.14.4/8.14.4) with ESMTP id r3Q3IJVV009411
(etc.)


SOURCE IP
---------
1.1.1.1

Если у вас уже есть заголовки в переменной, вы, очевидно, можете заменить -DTMPHEADERS='include(headers.txt)'на -DTMPHEADERS="$headers".

Кусалананда
источник