Вы можете сделать это с помощью ACLs (списки контроля доступа). Это отличная статья, на которую вам стоит взглянуть; ACL tutorial
Может быть, что-то вроде:
sed 'H;/#$/!d;s/^/\
/;x;/\n%/!d;s/.//;x;s/.*//;x'
Поскольку вы хотите, чтобы приглашение было перед ошибкой и после ошибки, оно включает в себя оба, за исключением подсказок, которые в противном случае появлялись бы как подсказка после одной ошибки, так и как подсказка перед следующей ошибкой. соответствовать вашему образцу вывода.
Намного проще, если мы включим оба приглашения, независимо от того, следуют ли ошибки друг за другом или нет:
sed 'H;/#$/!d;x;/\n%/!d'
Если бы вы хотели, чтобы перед ошибкой отображалось только приглашение, это также было бы намного проще:
sed '/#$/!{H;d;}
x;/\n%/!d'
Вероятно, лучший способ чтобы объяснить это, нужно перевести на более подробный язык, например perl
. В sed
пространство удержания похоже на статическую переменную, которая инициализируется пустой строкой, а пространство шаблонов - это переменная, которую sed
по очереди назначает каждой строке ввода. Примерно так:
$hold_space = "\n";
LINE: while ($pattern_space = <>) {
<sed commands go here>
print $pattern_space; # unless -n option is passed
}
Команда H
преобразуется в:
$hold_space .= $pattern_space;
Команда d
преобразуется в:
next LINE;
То есть прекратить выполнение команд, отбросить пространство шаблонов и начать заново со следующей строкой ввода.
x
меняет местами шаблон и удерживает пробел:
($pattern_space, $hold_space) = ($hold_space, $pattern_space);
Таким образом, последняя команда sed
преобразуется в:
$hold_space = "\n";
LINE: while ($pattern_space = <>) {
if (! ($pattern_space =~ /#$/)) { # anything other than a prompt
$hold_space .= $pattern_space;
next LINE;
}
($pattern_space, $hold_space) = ($hold_space, $pattern_space);
if (! ($pattern_space =~ /\n%/)) {
next LINE;
}
print $pattern_space;
}
Что может быть переписано более разборчиво как:
LINE: while ($pattern_space = <>) {
if ($pattern_space =~ /#$/)) {
if ($hold_space =~ /\n%/)) {
print $hold_space;
}
$hold_space = $pattern_space;
} else {
$hold_space .= $pattern_space;
}
}
Rename $ pattern_space
в $ line
и $ hold_space
в $ current_block
, и он становится еще более разборчивым.
Не уверен, что это то, что вам нужно, но:
#!/bin/bash
awk '
BEGIN {
err=0
}
/^SWE.*#$/ {
if (err) {
printf "%s\n%s", txt, $0
txt=""
err=0
} else {
txt=$0
}
next
}
/^% Invalid/ {
err=1
txt=txt "\n" $0
next
}
{
txt=txt "\n" $0
}
END {
print ""
}
' "$1"
Результат:
SWEs-elmPCI-A-01(config)#
class AutoQoS-VoIP-RTP-Trust
^
% Invalid input detected at '^' marker.
SWEs-elmPCI-A-01(config)#
class AutoQoS-VoIP-Control-Trust
^
% Invalid input detected at '^' marker.
SWEs-elmPCI-A-01(config)#
В качестве альтернативы, как я думал, с дополнительными строками для группировки:
awk '
BEGIN {
i = 0
sep="------------------------------------------------"
}
/^% Invalid/ {
printf "%s %3d\n%s\n%s\n%s\n",
sep, ++i, txt, $0, sep
txt=""
next
}
/^SWE.*#$/ {
txt=$0
next
}
txt != "" {
txt=txt "\n" $0
}
' "$1"
Результат:
------------------------------------------------ 1
SWEs-elmPCI-A-01(config)#
class AutoQoS-VoIP-RTP-Trust
^
% Invalid input detected at '^' marker.
------------------------------------------------
------------------------------------------------ 2
SWEs-elmPCI-A-01(config)#
class AutoQoS-VoIP-Control-Trust
^
% Invalid input detected at '^' marker.
------------------------------------------------