Извлечение блоков и значений серверов из конфигурации Nginx

Если вы заранее знаете, что хотите следить за тем, что делает программа, интерфейс ядра, такой как sysdigили SystemTap, может записывать контрольный журнал (или, возможно, strace, но это будет медленный и потребует идеальной оболочки вокруг программы для трассировки, и, надеюсь, sudoникогда не будет запущен... ). Вам также необходимо учитывать, что происходит, когда какая-либо другая программа создает выходные данные в рамках рассматриваемой программы :Должен ли также отслеживаться любой дочерний процесс?

perl -e 'qx(echo subshell-io > foo)'

Контрольный журнал каждого файла, затронутого каждой программой (, плюс другие метаданные, такие как пользователь и группа (s ), родительский pid и т. д. ), безусловно, возможен. Однако это может быть дорого в настройке, дорого в создании и дорого в обслуживании. Вероятно, потребуются некоторые средства фильтрации записей, чтобы исключить (некоторые, но, возможно, не все)/tmpзаписи в каталог, чтобы, возможно, объединить несколько вызовов записи passwd.tmp/ rename("passwd.tmp","passwd")в одну логическую операцию, а также как вы обрабатываете случай, когда интересующая вас программа изменяет, скажем,/etc/passwd(среди многих других возможных общих файлов ОС ), которые вы, вероятно, затем не хотите удалять вслепую при очистке после программы... или как вы справляетесь с делегированным Ввод-вывод, где ваша программа использует dbus, а затем какой-то другой процесс из-за какого-то случайного не -сообщения ввода-вывода по dbus генерирует ввод-вывод в другом месте из-за вашей программы...

4
21.06.2021, 13:08
2 ответа

Так как вы можете иметь более одного значения, разделенного пробелом -в строке, использование awkнемного сложно. Это абсолютно возможно в awk, но проще вместо этого использовать что-то вроде Perl:

$ perl -lne '
    if(/(^| )server / || eof){ 
        print join " ",@ll if $ll[0]; 
        @ll=(); 
    }
    /^(listen|root|server_name)\s+(\S[^;]+)/ && push @ll,$2' file 
80 domain1.com www.domain1.com html
80 domain2.com www.domain2.com /var/www/virtual/big.server.com/htdocs

-lneозначает «прочитать входной файл построчно (-n), удалить завершающие символы новой строки и добавить новую строку к каждому printвызову(-l)и запустить сценарий, заданный -eв каждой строке».

Код:

  • if(/(^| )server / || eof){ :этот раздел запустится, если текущая строка содержит слово server, окруженное пробелами, или в начале строки.

  • print join " ",@ll if $ll[0]; :если в настоящее время что-то хранится в массиве@ll(поэтому, если первый элемент массива, $ll[0], определен ), выведите содержимое массива, соединенного пробелом.

  • @ll=(); :очистить массив, чтобы мы могли получить информацию о следующем сервере.

  • /^(listen|root|server_name)\s+(\S[^;]+)/ && push @ll,$2':если эта строка начинается с одного из ключевых слов, а затем содержит один или несколько пробельных символов, найдите первый не -пробельный символ и как можно больше не-;символов до конца строки и добавьте этот (круглые скобки зафиксируют шаблон, так что «это» теперь$2)в массив @llдля печати.


А вот (уродливый )способ сделать это в awk:

$ awk '
    (/ server\s*\{/){ 
        if(out){
            print out
        }
        out=""
    } 
    ($1=="listen" || $1=="root" || $1=="server_name"){
        gsub(";",""); 
        $1=""; 
        gsub(/^ */,""); 
        out ? out=out" "$0 : out=$0
    }
    END{print out}' file 
80 domain1.com www.domain1.com html
80 domain2.com www.domain2.com /var/www/virtual/big.server.com/htdocs
5
28.07.2021, 11:23

Всякий раз, когда у вас есть тег (, он же имя, он же ключ )для пар значений во входных данных, я считаю, что лучше всего сначала создать массив этого сопоставления(f[])ниже, а затем вы можете просто распечатать любые значения, которые вы хотите в любом порядке, в котором вы хотите, и в любых условиях, которые вы хотите, просто получая доступ к значениям массива по их тегам.

Например, используя любой POSIX awk:

$ cat tst.awk
(NR > 1) && ($1 == "server") { prt() }
{
    tag = $1
    sub(/[[:space:]]*[^[:space:]]+[[:space:]]+/,"")
    sub(/;$/,"")
    f[tag] = $0
}
END { prt() }

function prt() {
    print f["listen"], f["server_name"], f["root"]
    delete f
}

$ awk -f tst.awk file
80 domain1.com www.domain1.com html
80 domain2.com www.domain2.com /var/www/virtual/big.server.com/htdocs

Если вы застряли с awk, отличным от -POSIX, который не поддерживает классы символов, просто замените [:space:]на \t(это пустой символ, затем обратную косую черту, а затемt).

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

4
28.07.2021, 11:23

Теги

Похожие вопросы