Thursday, February 9, 2012

IGMP Snooping-Enabled NLB on Cisco IOS

Microsoft NLB. What can I say...its free, and its Microsoft, you're not getting a premo solution. In a virtual environment, where a NLB member can move from physical server to physical server, some real fun begins. Many HOWTOs, including Cisco's own, will have you placing static CAM entries everywhere. BLEH! I hope to show you how to avoid that.

The MS rundown of NLB as a whole:
http://technet.microsoft.com/en-us/library/bb742455.aspx

Cisco's HOWTO (needs work as you'll see below):
http://www.cisco.com/en/US/products/hw/switches/ps708/products_configuration_example09186a0080a07203.shtml

There's a problem with this HOWTO from Cisco, its a bit messy. I want to give some credit first, I gathered some of this data from this forum post, I wouldn't have pieced it together otherwise.

Lets begin.

Microsoft NLB, when running in IGMP-enabled multicast mode(at least in 2008 R2), uses a IANA multicast MAC address, not a non-IANA one. This is an important point that I think has been overlooked by Cisco in their guide...because with this, you don't need the static CAM entry, you just need IGMP Snooping.

IGMP snooping won't work without IGMP joins being seen from the servers (virtual or otherwise). So you need a IGMP router on that VLAN/segment to advertise its presence so the Windows servers respond, and the snooping is performed. To do that, you need to either A) Enable PIM (and therefore IGMP) on the interface or B) Simply enable the interface to be a "IGMP Querier". I'll leave it up to the reader to find their own platform's Multicast configuration guide to find the commands, but I will warn you of two things:

1) Make sure multicast-routing is turned on(in the VRF your interface is on if you're doing VRFs)
2) You will not see any "joined groups" in your show ip igmp command output

Finally, Cisco's note about process switching. Bug CSCsw87563 addresses it for the 6500 platform, not sure about the others. In my environment, I've added zero CAM entries because the bug is "fixed" for my platform, if you're in the same boat, good for you. If not...you really should, process switching is terrible. Even if you are affected by this, you only need to put the static cam on the switch with the SVI. All downstream switches will snoop and L2 switch with ease.

>>>>>A quick bug toolkit search revealed nothing on the popular 3560/3750 and 4500 lines. I am very interested if anyone can find more info this process switch thing on other platforms....even NX-OS!

Finally, all my work has been around avoiding the use of tying a static CAM entry to a physical interface everywhere (to avoid switch flooding). You still need a single static ARP entry.

Monday, April 19, 2010

Disable NETBIOS with dhcpd

This was a difficult item to find...thanks to the dd-wrt wiki for the proper vendor string!!

NETBIOS is ancient...disabling NETBIOS altogether on networks(provided you are sure you want to do this) can be a good thing for both your network and your windows workstations.

For those of you using the default node-type, you will basically eliminate all netbios broadcasts on your network,and your workstations will ONLY use DNS for resolution, instead of DNS then WINS then NBT broadcasts.

Disadvantage is that you can no longer use tools like nbtstat to query machines on your network for their hostname (shouldn't you be using DDNS?) and connectivity using some 'short names' may be lost...but you should be using FQDNs whenever/wherever possible.

DHCP Option 43, value is "01:04:00:00:00:02"

The line in your ISC dhcpd config should be:

option vendor-encapsulated-options 01:04:00:00:00:02;

Tuesday, April 13, 2010

Infoblox API Scripting

Infoblox makes a pretty sweet little appliance, providing DNS(ISC BIND), DHCP(ISC DHCPD), TFTP/HTTP File distribution for your enterprise. More or less its a Linux appliance with a decent GUI on top of it for the aforementioned features.

One of my favorite features about it is its API, and I wanted to share some of my experience with it. Its entirely Perl based, and getting it setup was painful with me with CPAN, but their binary package on my CentOS box worked a treat. While (in my opinion) the API's documentation isn't the best, it has some very vague descriptions of many of the functions, and the examples they give aren't much for mass-modification purposes, but for creating new networks/ranges.

I'm not going to do a starter guide, you'll have to read their docs for that....I'll just provide some of my coding to supplement their existing documentation.

First of all, check out "ibcli", I used it as MY supplement to figure out the right data structure/method to use when writing this script.

The purpose of my script was to help facilitate moving from a single Infoblox HA pair to a failover set of geographically separated "Grid Member" HA pairs for even more DHCP fault-tolerance for our WAN users in case of a large network outage.

When moving to this setup, you must reconfigure every network and every DHCP range to "point" to the "failover set" consisting of a pairing between the two failover Infoblox Grid Members.
Since we have several hundred, DHCP Networks, my script was designed to dump to STDOUT all Networks and Ranges on the appliance before the change, then change all Networks/Ranges (save a few special setups I exempted) to point to the failover set, and then dump the "post operation" configuration to STDOUT for verification.

Please keep in mind that this script could definitely use a lot more catch statements for error handling, but I kept this pretty lean just to do this one job for me.

Without further adieu, see attached. Rename it from the .txt extension to .pl.

IBConvert Script

Tuesday, November 24, 2009

Adding a Cisco 3750 Switch to an Existing Stack

Another simple task that Cisco doesn't quite make 100% clear.

Let's say you have an existing Cisco 3750 Switch Stack and you have had a bit of an office redesign and you now need to add another member to the stack to add additional port capacity for the new users moving in.

This is mostly simple to do, but there are several checks to make along your journey, and hopefully I can point them out clearly.

  1. First, check the stacking status of your existing stack using the below command. It should say that the stack ring speed is "full". If it doesn't you need to ensure you have a complete stack "ring" thereby having redundant stacking paths on each switch.

    ZZStack#show switch stack-ring speed

    Stack Ring Speed : 32G
    Stack Ring Configuration: Full
    Stack Ring Protocol : StackWise


    See this publication for stack-wiring help:
    http://www.cisco.com/en/US/docs/switches/lan/catalyst3750/hardware/quick/guide/3750GSG3.html#wp49279

  2. Once you know your stack is a complete ring("full") you can safely break this ring to insert your new switch. ENSURE YOUR NEW SWITCH IS POWERED OFF. Rack this new switch adjacent to your existing switches. "Break" the ring in one place so you can wire your new switch so it fits nice and neat in this new stack, following the wiring schema linked above. Once everything is wiring in place, you may NOW power on your new switch.

  3. After a few minutes your switch will have booted and the existing stack should recognize it as joining the stack. You can verify its status with:

    ZZStack#show switch stack-ring speed

    Stack Ring Speed : 32G
    Stack Ring Configuration: Full
    Stack Ring Protocol : StackWise


    ZZStack#show switch
    Switch/Stack Mac Address : 0024.9803.8e80
    H/W Current
    Switch# Role Mac Address Priority Version State
    ----------------------------------------------------------
    *1 Master 0024.9803.8e80 15 0 Ready
    2 Member 0023.ac0f.7880 1 0 Ready
    3 Member 001a.e267.0080 1 0 Version Mismatch


    In this example switch 3 was added to the stack, the stack ring looks good, but on the switch status output, instead of saying "Ready" it says "Version Mismatch." You now need to ensure your switch gets the same IOS version as its stack-mates and reboots for this to take effect(see below).

    If your stack says your new switch is in the "Ready" state, you are in luck and you are done! (except for configuring your new user ports)

  4. Automatic Upgrade is a great thing in theory, but I've not had the best of luck with it. From what I can tell if your existing stack and this new member you are adding are running different IOS featuresets, the automatic upgrade will NOT WORK.

    To check to see if its working or not, check the log. If you see log entries resembling any of the below, it appears automatic upgrade is working as it should.
    ZZStack#show log
    ---snip---
    Nov 24 16:58:36.388 EST: %IMAGEMGR-6-AUTO_COPY_SW_INITIATED: Auto-copy-software process initiated for switch number(s) 3

    This shows that it has started the auto upgrade process. You can check the status with the "show archive status" command or by continually checking the log.

    If you see the below it was successful and is now rebooting this member switch so the correct IOS loads and it can finally join the stack as it should(and you should be done):
    ---snip---
    Nov 24 17:06:04.453 EST: %IMAGEMGR-6-AUTO_COPY_SW: Software successfully copied to
    Nov 24 17:06:04.453 EST: %IMAGEMGR-6-AUTO_COPY_SW: system(s) 3
    Nov 24 17:06:04.453 EST: %IMAGEMGR-6-AUTO_COPY_SW: Done copying software
    Nov 24 17:06:04.453 EST: %IMAGEMGR-6-AUTO_COPY_SW: Reloading system(s) 3


    If you don't see any of the above log entries, go on to the next step.

  5. This is the step they don't really explain well. Thankfully, the "Version Mismatch" state, while not activating any of its ports, does allow you to manipulate the flash filesystem of the inconsistent member so you can stage it from the main stack interface.

    If you made it to this step, it probably means there is a featureset mismatch(or some other problem) and you need to force this new member to take the IOS version that the stack is currently running. In this scenario, even the "archive copy-sw" command does not work, so you must either load the IOS bin file manually or use use the appropriate "archive download-sw" command with the "/allow-feature-upgrade" switch to load the IOS to the ENTIRE STACK again, including this new member(but you only need to reboot the new member). I prefer to use the archive command, its slow but its so easy!

    Here's the link to the software upgrade caveats/howtos for stack configurations(if it seems like I breezed through this last step):
    http://www.cisco.com/en/US/products/hw/switches/ps5023/products_configuration_example09186a00804799d7.shtml

Monday, August 24, 2009

Cisco Passive Interface Address-Family Warning

When you are configuring passive interfaces for the global VRF as well as other configured address-families, there is a difference between how the 12.4/12.4T Router IOS behaves and how a 6500/3750/3560 behaves. If you don't know what a passive interface is, this post isnt for you, but here is a step in the right direction.

On Routers, passive-interface settings are shared amongst ALL ADDRESS-FAMILIES, INCLUDING GLOBAL. While on the 3560/3750/6500 etc L3 Switch IOS, the address-families each have their own unique passive interface settings.

For instance:
router eigrp 1
network 10.0.0.0
no auto-summary
passive-interface default
!
address-family ipv4 vrf VRF-A
network 10.0.0.0
no auto-summary
exit-address-family
!
address-family ipv4 vrf VRF-B
  network 10.0.0.0
  no auto-summary
exit-address-family
end


The above code snippet on a Cisco Router would cause no EIGRP neighbor relationships to form, in either VRF or the global route table. However, on a Cisco L3 switch, the passive-interface command would ONLY apply to the global route table and each VRF will not have any of its member interfaces be acting as passive.

This final code snippet is not valid on a Router IOS, but is perfectly valid(and desired) on a L3 Switch IOS, with Po1 in the global route table, Po2 in VRF-A, and Po3 in VRF-B:
router eigrp 1
network 10.0.0.0
no auto-summary
passive-interface default
no passive-interface Po1
!
address-family ipv4 vrf VRF-A
network 10.0.0.0
no auto-summary
passive-interface default
no passive-itnerface Po2
exit-address-family
!
address-family ipv4 vrf VRF-B
network 10.0.0.0
no auto-summary
passive-interface default
no passive-interface Po3
exit-address-family
end

Wednesday, June 17, 2009

Renumbering a Cisco 3750 Stack

For those of you familiar with the Cisco 3750 switches, their killer feature is their ability to "stack". Stacking sets one switch as the "master" and utilizing stack cables out of the back of the switch, each switch in the stack appears as one. This allows for expandability, and ease of management.


Anywho, one annoyance of stacking 3750s is that an engineer building or adding to a stack can often install switches "out of order" meaning their stack ID does not match their order as-racked. Basically, most English(or any other Western language) speaking peoples. would assume that a group of 5 switches in a rack would be numbered 1-5, top to bottom. If this isnt the case, ASSumptions can lead to some mistakes and mistakes lead to fussy customers. Yes, this can be checked by pressing the mode button on the front of any stack member, but isnt it better to not worry with that and have it right from the beginning?


Anyway, as a best practice, I always set the order as racked to match the stack order. Its not as simple as issuing the renumber subcommand as it won't move your switch port configurations with the move, you have to do some trickery to move the configurations(it even warns you of this when you hit the commands). If you want to renumber switches in a stack, here is a little HOWTO, since Cisco really doesn't go over this scenario, and I've done it a few times.


*************
Example:
*************
Stack of 2 switches in a rack, Switch 2 is on top, switch 1 is on the bottom.

Step 1: Prime the switches by setting their new stack numbers
We want 2 to become 1 and 2 to become 2, right?

In config mode:
switch 1 renumber 2
switch 2 renumber 1


Then write your config...simple enough.



Step 2:
Copy the startup config to your favorite text editor via screen scrape or file transfer. Do a find replace on all 2/0/ and replace with X/0/ and then find replace 1/0/ with 2/0/, and finally X/0/ with 1/0/. Basically you have flip-flopped all the port configs between the two switches using the power of find/replace.

Step 3:
Upload the file you edited above and have it overwrite the startup config of the stack. Reload the stack

Step 4:
Test. (of course).

Wednesday, April 22, 2009

Ultimate "sed" guide, manipulate many files on *nix!

Its not often I directly rip off others' content, but today is one of those days. (all credit is given, however ;-))

Sed is the *nix utility for stream editing...basically its a great file manipulator. Below you will see a bunch of GREAT uses for it. I've cached a copy here in case the internets eat it alive.

Grabbed from here: http://www.student.northpark.edu/pemente/sed/sed1line.txt
-------------------------------------------------------------------------
HANDY ONE-LINERS FOR SED (Unix stream editor) Apr. 26, 2004
compiled by Eric Pement - pemente[at]northpark[dot]edu version 5.4
Latest version of this file is usually at:
http://sed.sourceforge.net/sed1line.txt
http://www.student.northpark.edu/pemente/sed/sed1line.txt
This file is also available in Portuguese at:
http://www.lrv.ufsc.br/wmaker/sed_ptBR.html

FILE SPACING:

# double space a file
sed G

# double space a file which already has blank lines in it. Output file
# should contain no more than one blank line between lines of text.
sed '/^$/d;G'

# triple space a file
sed 'G;G'

# undo double-spacing (assumes even-numbered lines are always blank)
sed 'n;d'

# insert a blank line above every line which matches "regex"
sed '/regex/{x;p;x;}'

# insert a blank line below every line which matches "regex"
sed '/regex/G'

# insert a blank line above and below every line which matches "regex"
sed '/regex/{x;p;x;G;}'

NUMBERING:

# number each line of a file (simple left alignment). Using a tab (see
# note on '\t' at end of file) instead of space will preserve margins.
sed = filename | sed 'N;s/\n/\t/'

# number each line of a file (number on left, right-aligned)
sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /'

# number each line of file, but only print numbers if line is not blank
sed '/./=' filename | sed '/./N; s/\n/ /'

# count lines (emulates "wc -l")
sed -n '$='

TEXT CONVERSION AND SUBSTITUTION:

# IN UNIX ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format
sed 's/.$//' # assumes that all lines end with CR/LF
sed 's/^M$//' # in bash/tcsh, press Ctrl-V then Ctrl-M
sed 's/\x0D$//' # gsed 3.02.80, but top script is easier

# IN UNIX ENVIRONMENT: convert Unix newlines (LF) to DOS format
sed "s/$/`echo -e \\\r`/" # command line under ksh
sed 's/$'"/`echo \\\r`/" # command line under bash
sed "s/$/`echo \\\r`/" # command line under zsh
sed 's/$/\r/' # gsed 3.02.80

# IN DOS ENVIRONMENT: convert Unix newlines (LF) to DOS format
sed "s/$//" # method 1
sed -n p # method 2

# IN DOS ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format
# Can only be done with UnxUtils sed, version 4.0.7 or higher.
# Cannot be done with other DOS versions of sed. Use "tr" instead.
sed "s/\r//" infile >outfile # UnxUtils sed v4.0.7 or higher
tr -d \r <infile >outfile # GNU tr version 1.22 or higher

# delete leading whitespace (spaces, tabs) from front of each line
# aligns all text flush left
sed 's/^[ \t]*//' # see note on '\t' at end of file

# delete trailing whitespace (spaces, tabs) from end of each line
sed 's/[ \t]*$//' # see note on '\t' at end of file

# delete BOTH leading and trailing whitespace from each line
sed 's/^[ \t]*//;s/[ \t]*$//'

# insert 5 blank spaces at beginning of each line (make page offset)
sed 's/^/ /'

# align all text flush right on a 79-column width
sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # set at 78 plus 1 space

# center all text in the middle of 79-column width. In method 1,
# spaces at the beginning of the line are significant, and trailing
# spaces are appended at the end of the line. In method 2, spaces at
# the beginning of the line are discarded in centering the line, and
# no trailing spaces appear at the end of lines.
sed -e :a -e 's/^.\{1,77\}$/ & /;ta' # method 1
sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' # method 2

# substitute (find and replace) "foo" with "bar" on each line
sed 's/foo/bar/' # replaces only 1st instance in a line
sed 's/foo/bar/4' # replaces only 4th instance in a line
sed 's/foo/bar/g' # replaces ALL instances in a line
sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # replace the next-to-last case
sed 's/\(.*\)foo/\1bar/' # replace only the last case

# substitute "foo" with "bar" ONLY for lines which contain "baz"
sed '/baz/s/foo/bar/g'

# substitute "foo" with "bar" EXCEPT for lines which contain "baz"
sed '/baz/!s/foo/bar/g'

# change "scarlet" or "ruby" or "puce" to "red"
sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g' # most seds
gsed 's/scarlet\|ruby\|puce/red/g' # GNU sed only

# reverse order of lines (emulates "tac")
# bug/feature in HHsed v1.5 causes blank lines to be deleted
sed '1!G;h;$!d' # method 1
sed -n '1!G;h;$p' # method 2

# reverse each character on the line (emulates "rev")
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'

# join pairs of lines side-by-side (like "paste")
sed '$!N;s/\n/ /'

# if a line ends with a backslash, append the next line to it
sed -e :a -e '/\\$/N; s/\\\n//; ta'

# if a line begins with an equal sign, append it to the previous line
# and replace the "=" with a single space
sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'

# add commas to numeric strings, changing "1234567" to "1,234,567"
gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta' # GNU sed
sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' # other seds

# add commas to numbers with decimal points and minus signs (GNU sed)
gsed ':a;s/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g;ta'

# add a blank line every 5 lines (after lines 5, 10, 15, 20, etc.)
gsed '0~5G' # GNU sed only
sed 'n;n;n;n;G;' # other seds

SELECTIVE PRINTING OF CERTAIN LINES:

# print first 10 lines of file (emulates behavior of "head")
sed 10q

# print first line of file (emulates "head -1")
sed q

# print the last 10 lines of a file (emulates "tail")
sed -e :a -e '$q;N;11,$D;ba'

# print the last 2 lines of a file (emulates "tail -2")
sed '$!N;$!D'

# print the last line of a file (emulates "tail -1")
sed '$!d' # method 1
sed -n '$p' # method 2

# print only lines which match regular expression (emulates "grep")
sed -n '/regexp/p' # method 1
sed '/regexp/!d' # method 2

# print only lines which do NOT match regexp (emulates "grep -v")
sed -n '/regexp/!p' # method 1, corresponds to above
sed '/regexp/d' # method 2, simpler syntax

# print the line immediately before a regexp, but not the line
# containing the regexp
sed -n '/regexp/{g;1!p;};h'

# print the line immediately after a regexp, but not the line
# containing the regexp
sed -n '/regexp/{n;p;}'

# print 1 line of context before and after regexp, with line number
# indicating where the regexp occurred (similar to "grep -A1 -B1")
sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h

# grep for AAA and BBB and CCC (in any order)
sed '/AAA/!d; /BBB/!d; /CCC/!d'

# grep for AAA and BBB and CCC (in that order)
sed '/AAA.*BBB.*CCC/!d'

# grep for AAA or BBB or CCC (emulates "egrep")
sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # most seds
gsed '/AAA\|BBB\|CCC/!d' # GNU sed only

# print paragraph if it contains AAA (blank lines separate paragraphs)
# HHsed v1.5 must insert a 'G;' after 'x;' in the next 3 scripts below
sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;'

# print paragraph if it contains AAA and BBB and CCC (in any order)
sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d'

# print paragraph if it contains AAA or BBB or CCC
sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d
gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d' # GNU sed only

# print only lines of 65 characters or longer
sed -n '/^.\{65\}/p'

# print only lines of less than 65 characters
sed -n '/^.\{65\}/!p' # method 1, corresponds to above
sed '/^.\{65\}/d' # method 2, simpler syntax

# print section of file from regular expression to end of file
sed -n '/regexp/,$p'

# print section of file based on line numbers (lines 8-12, inclusive)
sed -n '8,12p' # method 1
sed '8,12!d' # method 2

# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3, efficient on large files

# beginning at line 3, print every 7th line
gsed -n '3~7p' # GNU sed only
sed -n '3,${p;n;n;n;n;n;n;}' # other seds

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p' # case sensitive

SELECTIVE DELETION OF CERTAIN LINES:

# print all of file EXCEPT section between 2 regular expressions
sed '/Iowa/,/Montana/d'

# delete duplicate, consecutive lines from a file (emulates "uniq").
# First line in a set of duplicate lines is kept, rest are deleted.
sed '$!N; /^\(.*\)\n\1$/!P; D'

# delete duplicate, nonconsecutive lines from a file. Beware not to
# overflow the buffer size of the hold space, or else use GNU sed.
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'

# delete all lines except duplicate lines (emulates "uniq -d").
sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'

# delete the first 10 lines of a file
sed '1,10d'

# delete the last line of a file
sed '$d'

# delete the last 2 lines of a file
sed 'N;$!P;$!D;$d'

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D' # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba' # method 2

# delete every 8th line
gsed '0~8d' # GNU sed only
sed 'n;n;n;n;n;n;n;d;' # other seds

# delete ALL blank lines from a file (same as "grep '.' ")
sed '/^$/d' # method 1
sed '/./!d' # method 2

# delete all CONSECUTIVE blank lines from file except the first; also
# deletes all blank lines from top and end of file (emulates "cat -s")
sed '/./,/^$/!d' # method 1, allows 0 blanks at top, 1 at EOF
sed '/^$/N;/\n$/D' # method 2, allows 1 blank at top, 0 at EOF

# delete all CONSECUTIVE blank lines from file except the first 2:
sed '/^$/N;/\n$/N;//D'

# delete all leading blank lines at top of file
sed '/./,$!d'

# delete all trailing blank lines at end of file
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # works on all seds
sed -e :a -e '/^\n*$/N;/\n$/ba' # ditto, except for gsed 3.02*

# delete the last line of each paragraph
sed -n '/^$/{p;h;};/./{x;/./p;}'

SPECIAL APPLICATIONS:

# remove nroff overstrikes (char, backspace) from man pages. The 'echo'
# command may need an -e switch if you use Unix System V or bash shell.
sed "s/.`echo \\\b`//g" # double quotes required for Unix environment
sed 's/.^H//g' # in bash/tcsh, press Ctrl-V and then Ctrl-H
sed 's/.\x08//g' # hex expression for sed v1.5

# get Usenet/e-mail message header
sed '/^$/q' # deletes everything after first blank line

# get Usenet/e-mail message body
sed '1,/^$/d' # deletes everything up to first blank line

# get Subject header, but remove initial "Subject: " portion
sed '/^Subject: */!d; s///;q'

# get return address header
sed '/^Reply-To:/q; /^From:/h; /./d;g;q'

# parse out the address proper. Pulls out the e-mail address by itself
# from the 1-line return address header (see preceding script)
sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//'

# add a leading angle bracket and space to each line (quote a message)
sed 's/^/> /'

# delete leading angle bracket & space from each line (unquote a message)
sed 's/^> //'

# remove most HTML tags (accommodates multiple-line tags)
sed -e :a -e 's/<[^>]*>//g;/</N;//ba'

# extract multi-part uuencoded binaries, removing extraneous header
# info, so that only the uuencoded portion remains. Files passed to
# sed must be passed in the proper order. Version 1 can be entered
# from the command line; version 2 can be made into an executable
# Unix shell script. (Modified from a script by Rahul Dhesi.)
sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode # vers. 1
sed '/^end/,/^begin/d' "$@" | uudecode # vers. 2

# zip up each .TXT file individually, deleting the source file and
# setting the name of each .ZIP file to the basename of the .TXT file
# (under DOS: the "dir /b" switch returns bare filenames in all caps).
echo @echo off >zipup.bat
dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat

TYPICAL USE: Sed takes one or more editing commands and applies all of
them, in sequence, to each line of input. After all the commands have
been applied to the first input line, that line is output and a second
input line is taken for processing, and the cycle repeats. The
preceding examples assume that input comes from the standard input
device (i.e, the console, normally this will be piped input). One or
more filenames can be appended to the command line if the input does
not come from stdin. Output is sent to stdout (the screen). Thus:

cat filename | sed '10q' # uses piped input
sed '10q' filename # same effect, avoids a useless "cat"
sed '10q' filename > newfile # redirects output to disk

For additional syntax instructions, including the way to apply editing
commands from a disk file instead of the command line, consult "sed &
awk, 2nd Edition," by Dale Dougherty and Arnold Robbins (O'Reilly,
1997; http://www.ora.com), "UNIX Text Processing," by Dale Dougherty
and Tim O'Reilly (Hayden Books, 1987) or the tutorials by Mike Arst
distributed in U-SEDIT2.ZIP (many sites). To fully exploit the power
of sed, one must understand "regular expressions." For this, see
"Mastering Regular Expressions" by Jeffrey Friedl (O'Reilly, 1997).
The manual ("man") pages on Unix systems may be helpful (try "man
sed", "man regexp", or the subsection on regular expressions in "man
ed"), but man pages are notoriously difficult. They are not written to
teach sed use or regexps to first-time users, but as a reference text
for those already acquainted with these tools.

QUOTING SYNTAX: The preceding examples use single quotes ('...')
instead of double quotes ("...") to enclose editing commands, since
sed is typically used on a Unix platform. Single quotes prevent the
Unix shell from intrepreting the dollar sign ($) and backquotes
(`...`), which are expanded by the shell if they are enclosed in
double quotes. Users of the "csh" shell and derivatives will also need
to quote the exclamation mark (!) with the backslash (i.e., \!) to
properly run the examples listed above, even within single quotes.
Versions of sed written for DOS invariably require double quotes
("...") instead of single quotes to enclose editing commands.

USE OF '\t' IN SED SCRIPTS: For clarity in documentation, we have used
the expression '\t' to indicate a tab character (0x09) in the scripts.
However, most versions of sed do not recognize the '\t' abbreviation,
so when typing these scripts from the command line, you should press
the TAB key instead. '\t' is supported as a regular expression
metacharacter in awk, perl, and HHsed, sedmod, and GNU sed v3.02.80.

VERSIONS OF SED: Versions of sed do differ, and some slight syntax
variation is to be expected. In particular, most do not support the
use of labels (:name) or branch instructions (b,t) within editing
commands, except at the end of those commands. We have used the syntax
which will be portable to most users of sed, even though the popular
GNU versions of sed allow a more succinct syntax. When the reader sees
a fairly long command such as this:

sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d

it is heartening to know that GNU sed will let you reduce it to:

sed '/AAA/b;/BBB/b;/CCC/b;d' # or even
sed '/AAA\|BBB\|CCC/b;d'

In addition, remember that while many versions of sed accept a command
like "/one/ s/RE1/RE2/", some do NOT allow "/one/! s/RE1/RE2/", which
contains space before the 's'. Omit the space when typing the command.

OPTIMIZING FOR SPEED: If execution speed needs to be increased (due to
large input files or slow processors or hard disks), substitution will
be executed more quickly if the "find" expression is specified before
giving the "s/.../.../" instruction. Thus:

sed 's/foo/bar/g' filename # standard replace command
sed '/foo/ s/foo/bar/g' filename # executes more quickly
sed '/foo/ s//bar/g' filename # shorthand sed syntax

On line selection or deletion in which you only need to output lines
from the first part of the file, a "quit" command (q) in the script
will drastically reduce processing time for large files. Thus:

sed -n '45,50p' filename # print line nos. 45-50 of a file
sed -n '51q;45,50p' filename # same, but executes much faster

If you have any additional scripts to contribute or if you find errors
in this document, please send e-mail to the compiler. Indicate the
version of sed you used, the operating system it was compiled for, and
the nature of the problem. Various scripts in this file were written
or contributed by:

Al Aab <af137@freenet.toronto.on.ca> # "seders" list moderator
Edgar Allen <era@sky.net> # various
Yiorgos Adamopoulos <adamo@softlab.ece.ntua.gr>
Dale Dougherty <dale@songline.com> # author of "sed & awk"
Carlos Duarte <cdua@algos.inesc.pt> # author of "do it with sed"
Eric Pement <pemente@northpark.edu> # author of this document
Ken Pizzini <ken@halcyon.com> # author of GNU sed v3.02
S.G. Ravenhall <stew.ravenhall@totalise.co.uk> # great de-html script
Greg Ubben <gsu@romulus.ncsc.mil> # many contributions & much help
-------------------------------------------------------------------------