I have a file that I need to find each interface that has move-group on the interface line and print this line if the lines under the interface does Not have "filter-shared 14".
Example file:
interface 1/1/1/0 move-group
decription one one one zero
no shut
filter-shared 14
accounting-policy 5
shared-address 0
interface 1/1/1/1 move-group
decription one one one one
no shut
accounting-policy 5
shared-address 0
interface 1/1/1/2 move-group
decription one one one two
no shut
filter-shared 14
accounting-policy 5
shared-address 0
interface 1/1/1/3 move-group
decription one one one three
no shut
accounting-policy 5
shared-address 0
interface 1/1/1/4 permanent-group
decription one one one four
no shut
accounting-policy 5
shared-address 0
I only wish to print out the interface line that does have "filter-shared 14" under it.
So the output would look like this:
Stash each interface line in a variable a, and 0 in another b, and as your seaarch forward, look for filter-shared 14, and if you find it, st the second var b to 1, and at the next interface line or EOF if b still a zero, print the stash a before stashing the new interface line. So, in code the last bit comes first!
Thank you Scrutinizer, that works. But it skips the first line of the file if there is a match. I think it's because x is empty until after the first line.
Note that there are two parts. The first puts empty lines around the records, the "x" is an empty variable, so that an empty line gets printed before that start of each record.
This then enables the second awk to use RS= , a special value so that records can be separated by blank lines and thus become multi-line records. So for example the first record becomes:
interface 1/1/1/0 move-group
decription one one one zero
no shut
filter-shared 14
accounting-policy 5
shared-address 0
Because the fields separator FS is set to \n , the first field ( $1 ) is equal to the first line of such a multiline record..
Scrutinizer,
Your awk line works very well, thank you. I was using a test file for it first but when using it on the actual files, it worked out fine.
Thanks again!
This longish post is intended to show a general technique for working with paragraphs or stanzas of data. Each stanza is transformed so that a copy of it becomes a single, standard text line, embedded newlines are converted to some other character (in the specific case "|"). This creates an intermediate structure that one could call a super-line.
The super-lines are then manipulated to obtain a final set of super-lines that conform to the requirements. Finally, the super-lines are split back to normal, and final filtering can be done.
This script performs that combination of operations. The creation of super-lines can be done with awk, perl, etc. I used a perl utility from github called cat0par (see script for link). The script also uses a few local tools such pll, specimen, etc.
#!/usr/bin/env bash
# @(#) s1 Demonstrate join / split of super-line to search embedded string.
# See:
# https://github.com/jakobi/script-archive/blob/master/cli.list.grep/cat0par
# or:
# https://raw.githubusercontent.com/jakobi/script-archive/master/cli.list.grep/cat0par
# Utility functions: print-as-echo, print-line-with-visual-space, debug.
# export PATH="/usr/local/bin:/usr/bin:/bin"
LC_ALL=C ; LANG=C ; export LC_ALL LANG
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
db() { : ; }
pe
what $( which pll cat0par )
C=$HOME/bin/context && [ -f $C ] && $C specimen cat0par grep sed pll
FILE=${1-data1}
pl " Sample input data file $FILE:"
specimen 5 $FILE
# Collect and join all lines in an "interface" stanza into a super-line.
# Select "move-group: super-lines.
# Omit "filter-shared 14" super-lines.
# Split super-lines back into stanzas.
# Select "interface" lines.
rm -f f[1-9]
pl " Results:"
cat0par -nl -nonl='|' -start "interface" $FILE |
tee f1 |
grep "move-group" |
tee f2 |
grep -v "filter-shared 14" |
tee f3 |
sed 's/|/\n/'g |
tee f4 |
grep "interface"
pl " Content of intermediate files:"
pll f?
exit 0
producing:
$ ./s1
pll Print long-line, section, trim, shorten to width as necessary.
cat0par Combine/split lines to stanza/groups/superlines.
Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
Distribution : Debian 5.0.8 (lenny, workstation)
bash GNU bash 3.2.39
specimen (local) 1.17
cat0par (local) 1.3
grep GNU grep 2.5.3
sed GNU sed version 4.1.5
pll (local) 1.22
-----
Sample input data file data1:
Edges: 5:0:5 of 27 lines in file "data1"
interface 1/1/1/0 move-group
decription one one one zero
no shut
filter-shared 14
accounting-policy 5
---
interface 1/1/1/4 permanent-group
decription one one one four
no shut
accounting-policy 5
shared-address 0
-----
Results:
interface 1/1/1/1 move-group
interface 1/1/1/3 move-group
-----
Content of intermediate files:
(Longest line: 143; fit into lines of length 78)
1 2 3 ... 11 12 13
12345678901234567890123456789012345...78901234567890123456789012345678901
FILE = f1
interface 1/1/1/0 move-group| d...unting-policy 5| shared-address
interface 1/1/1/1 move-group| d...unting-policy 5| shared-address
interface 1/1/1/2 move-group| d...unting-policy 5| shared-address
interface 1/1/1/3 move-group| d...unting-policy 5| shared-address
interface 1/1/1/4 permanent-group| ...unting-policy 5| shared-address
FILE = f2
interface 1/1/1/0 move-group| d...unting-policy 5| shared-address
interface 1/1/1/1 move-group| d...unting-policy 5| shared-address
interface 1/1/1/2 move-group| d...unting-policy 5| shared-address
interface 1/1/1/3 move-group| d...unting-policy 5| shared-address
FILE = f3
interface 1/1/1/1 move-group| d...unting-policy 5| shared-address
interface 1/1/1/3 move-group| d...unting-policy 5| shared-address
FILE = f4
interface 1/1/1/1 move-group
decription one one one one
no shut
accounting-policy 5
shared-address 0
interface 1/1/1/3 move-group
decription one one one three
no shut
accounting-policy 5
shared-address 0
The intermediate files are displayed to show the progress of the operation. They can be omitted for production work.
sed -n '
:loop
N
/\ninterface/!{
$!{
s/\n/:/
b loop
}
s/$/\
/
}
/filter-shared 14/!{
s/:.*\n/\
/
P
}
s/.*\n//
b loop
' file
Narrative: Set a branch tag 'loop' for looping, add another input line to the buffer, if the final line in the buffer is not an interface line then if it is not EOF then turn the linefeed into a colon and go back to loop else for EOF put a linefeed on the end of the line, then if there is no key string in the buffer, remove all but the interface lines and print the first interface line, discard the first line(s) in the buffer and loop back for more lines.
Scrutinizer, your solution works but it is so slow. I have 4400 large files to process and the awk statement I had been using was very fast. If I could just get it to add the next line, it would be perfect.
nawk 'END {if (!ok) print r} /interface/ && /move-group/ {if (!ok) print r; r = $0; ok = x}/filter-shared 14/ {r = r RS $0; ok++}' inputfile