tcl регулярное выражение не работает должным образом при использовании с именем переменной - PullRequest
0 голосов
/ 07 июня 2018

Я использую tcl для сопоставления с образцом.Ниже приведена строка, для которой я выполняю сопоставление:

ps -ef | grep ipqosmgr
root     17255 17136  0 22:34 ttyS0    00:00:00 grep ipqosmgr
root     28986 17731  0 Jun05 ?        00:02:01 /isan/bin/ipqosmgr

Как правило, я хотел бы, чтобы 3-я строка

root     28986 17731  0 Jun05 ?        00:02:01 /isan/bin/ipqosmgr

, так как я хотел бы, чтобы идентификатор процесса ассоциировался с процессом.

Когда я использую следующее регулярное выражение, оно работает как положено:

% foreach line [split $output \n] {
    if { [ regexp -nocase {root\s+([0-9]+)\s+.*(/isan/bin/ipqosmgr)} $line - value ] } {
        puts $line
    }
}
root     28986 17731  0 Jun05 ?        00:02:01 /isan/bin/ipqosmgr
% puts $value
28986
% 

Однако я хотел бы, чтобы этот код запускался для нескольких процессов и, следовательно, поместил его в функцию с $ process , который будет содержать значение процесса.Когда я использую то же регулярное выражение с переменной $ process , он завершается ошибкой.

% puts $process
ipqosmgr
%
% foreach line [split $output \n] {
    if { [ regexp -nocase {root\s+([0-9]+)\s+.*(/isan/bin/$process)} $line - value ] } {
        puts $line
    }
}
% 
% puts $value
can't read "value": no such variable
% 

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

Ответы [ 3 ]

0 голосов
/ 07 июня 2018

Вы можете подготовить регулярное выражение с помощью format, как показано ниже:

foreach line [split $output \n] {
    set regex [format {root\s+([0-9]+)\s+.*(/isan/bin/%s)} $process]
    if { [ regexp -nocase $regex $line - value ] } {
        puts $line
    }
}

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

0 голосов
/ 07 июня 2018

Использовать подстановку переменных с помощью команды subst .Также, если указаны какие-либо из -nobackslashes, -nocommands или -novariables, то соответствующие замены не выполняются.Например, если указано -nocommands, подстановка команд не выполняется: открывающие и закрывающие скобки обрабатываются как обычные символы без специальной интерпретации.

% set output "
root     17255 17136  0 22:34 ttyS0    00:00:00 grep ipqosmgr
root     28986 17731  0 Jun05 ?        00:02:01 /isan/bin/ipqosmgr
"

и с набором переменных

% set process "ipqosmgr"

Вы могли бы очень хорошо сделать,

% foreach line [split $output \n] {
    if { [ regexp -nocase [subst -nocommands -nobackslashes {root\s+([0-9]+)\s+.*(/isan/bin/$process)}] $line - value ] } {
        puts $line
    }
}
root     28986 17731  0 Jun05 ?        00:02:01 /isan/bin/ipqosmgr

делает матч, как ожидалось

% puts $value
28986
0 голосов
/ 07 июня 2018

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

regexp -nocase "root\\s+(\[0-9\]+)\\s+.*(/isan/bin/$process)" $line - value

См. демо Tcl онлайн .

Здесь,

  • root- подстрока root
  • \\s+ - анализируется как \s+ - 1 или более пробельных символов
  • (\[0-9\]+) - анализируется как ([0-9]+) - группа захвата 1 - 1 или болеецифры
  • \\s+ - 1 или более пробелов
  • .* - любые 0+ символов
  • (/isan/bin/$process) - проанализировано как (/isan/bin/ipqosmgr) - группа захвата 1 соответствует/isan/bin/ipqosmgr подстрока (или любая /isan/bin/ + $process).
...