SED Hints

From PeformIQ Upgrade
Jump to navigation Jump to search

From - https://www.ict.griffith.edu.au/anthony/info/shell/sed.hints

-------------------------------------------------------------------------------
Also see  regex.hints  for hints and tips of matching regular expressions
And sed 1 liners
  http://sed.sourceforge.net/sed1line.txt
Also examples from the gnu "info sed"

------------------------------------------------------------------------------
Print specific lines

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

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


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

print the next-to-the-last line of a file
  sed -e '$!{h;d;}' -e x              # for 1-line files, print blank line
  sed -e '1{$q;}' -e '$!{h;d;}' -e x  # for 1-line files, print the line
  sed -e '1{$d;}' -e '$!{h;d;}' -e x  # for 1-line files, print nothing

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

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


------------------------------------------------------------------------------
Delete between Markers AAAA and BBBB

Inclusive delete (delete start and end)
  sed '/AAAA/,/BBBB/d'

Exclusive delete (output start and end)
  sed '1,/AAAA/p; /BBBB/,$p; d'
or
  sed '/AAAA/,/BBBB/{ /AAAA/p; /BBBB/p; d }'

delete end but output start
  sed '/AAAA/p; /AAAA/,/BBBB/d'
or
  sed '/AAAA/,/BBBB/{ /AAAA/p; d }'

delete start but output end
  sed '/AAAA/,/BBBB/{ /BBBB/p; d }'
or
  sed '/BBBB/p; /AAAA/,/BBBB/d }'

See next...

------------------------------------------------------------------------------
Print lines between markers AAAA to BBBB

Including markers
  sed -n '/AAAA/,$p; /BBBB/q' file

Excluding the end marker
  sed -n '/BBBB/q; /AAAA/,$p' file
or
  sed -n '/AAAA/,$p; /BBBB/Q' file

Excluding both markers
  sed -n '/BBBB/q; 1,/AAAA/d; p' file
or
  sed '1,/AAAA/d; /BBBB/Q' file

-------------------------------------------------------------------------------
Line numbers

left aligned
  sed = file | sed 'N;s/\n/\t/'

right aligned
  sed = filename | sed 'N; s/^/     /; s/ *\(.\{6,\}\)\n/\1  /'

counting lines ("sed" only no "wc")

  sed -n '$=' file

------------------------------------------------------------------------------
Delete ALL blank lines
  sed '/^$/d' file

Delete multiple blank lines (paragraph separators)
  sed '/^$/{ N; /^\n$/D; }' file
or
  sed '/./,/^$/!d' file

===============================================================================
Programming with sed....

------------------------------------------------------------------------------
Delimiting "sed" Delimetors (also see next)

Say you want to search for a path name that contains slashes `/'
unfortunatally these are the sed regular expresion delimiters so you
need to escape the slashes before you can search for it. This is not as
easy as it sounds.

old_path="/some/path/to/look/for"
new_path="/some/path/to/look/for"

old_path=`echo "$old_path" | sed 's/\//\\\\\//g'`
new_path=`echo "$new_path" | sed 's/\//\\\\\//g'`

sed 's'"$old_path"'/'"$new_path"'/g' $old_file > $new_file

-------------------------------------------------------------------------------
Sed with arbatitry patterns

   #!/bin/sh
   #  substitute {pattern} {replacement}
   #
   sed 's/'"$1"'/'"$2"'/g

That's OK provided you know for certain that $1 will never contain a "/"
or "\", and $2 will never contain a "/", "\" or "&".  If $1 and $2 are
completely arbitrary you need to do something like:

    pat=`echo "$1" | sed 's:[/\\]:\\&:g'`
    rep=`echo "$2" | sed 's:[/\\&]:\\&:g'`
    sed "s/$pat/$rep/g"

Is there a problem with  """ or "`" in patterns?  -- seems not

-------------------------------------------------------------------------------
Sed Programming Methology Example:

This sed script grabs a 'face' file (which always starts with a space or tab)
and repositions it correctly at the end of the mail header (denoted by a
absolutely blank line). NOTE the use of lables.

  cat $FACE - $SIGNED | sed -n '
    # first collect the new face at the start of the input
    1 { s/^/X-Face:/; h; d; }
      /^[ \t]/{H;d;}
    # read the header; if X-face found just copy all
    : head
      /^X-Face:/ b body
      /^$/ b face
      p; n; b head
    # output a face at end of header
    :face
      x; p; g; p; n
    # just copy the rest of the file
    : body
      p; n; b body
  ' | /lib/sendmail "$@"

-------------------------------------------------------------------------------
Adding a newline to sed (just add return -- messy)
  bourne shells:
       sed 's/;$/; }\
       /' filename

  Csh family:
       sed 's/;$/; }\\
       /' filename

Of course you can always use a tr which is slower but neater

      sed 's/;$/; }@/' | tr '@' '\012'

GNU sed allows you to use \r  (for return)
But uses \n on the input side.  Do not use \n on output as that is 'null'

      sed 's/;$/; }\r/'

In a similar way it allows the use of \t for tab.

-------------------------------------------------------------------------------
Moving a line to the start of the file
EG
     something1                          this
     something2            ====>         something1
     this                                something2
     something3                          something3

  sed -n '
    /this/!H                      # if no match append to hold space
    /this/{x; H; }                # found so exhange and append (prepend)
    ${g; s/\n//; p; }' <infile    # if last line get and print hold
OR
  sed '1,/this/{                  # until found
    /this/!{H; d; }               # if not it put in hold (no print)
    G; s-\n--; }' infile          # otherwise output hold
                                  # no match will continue print rest of file

-------------------------------------------------------------------------------
Word Division -- sed and non-sed version

    Name=`echo $DISPLAY | sed 's/:.*//'`

can be done faster with

    oldIFS=$IFS; IFS=.; set -- $DISPLAY; IFS=$oldIFS; Name=$1;

no fork, totally internal to shell

------------------------------------------------------------------------------
Increment the number given

  sed -e '
    #Add zero to start if needed
    /^9*$/ s/^/0/
    # separate changing/unchanged digits with an x (and hold)
    s/.9*$/x&/
    h
    # increment digits
    s/^.*x//
    y/0123456789/1234567890/
    # merge unchanged with changed
    x
    s/x.*$//
    G
    s/\n//
    '

Alturnative without using the hold buffer

  sed -e '
    /[^0-9]/ d

    # replace all leading 9s by _ (any non-digit could be used)
    :d
    s/9\(_*\)$/_\1/
    td

    # incr last digit only.  The first line adds a most-significant
    # digit of 1 if we have to add a digit.
    #
    # The t commands are not necessary, but make the thing faster

    s/^\(_*\)$/1\1/; tn
    s/8\(_*\)$/9\1/; tn
    s/7\(_*\)$/8\1/; tn
    s/6\(_*\)$/7\1/; tn
    s/5\(_*\)$/6\1/; tn
    s/4\(_*\)$/5\1/; tn
    s/3\(_*\)$/4\1/; tn
    s/2\(_*\)$/3\1/; tn
    s/1\(_*\)$/2\1/; tn
    s/0\(_*\)$/1\1/; tn

    :n
    y/_/0/
    '

-------------------------------------------------------------------------------
Count 'a's on a line

  sed -e '
    # convert groups of ten to a higher order
    # The t and b are not necessary, but is faster
    t a
    : a;  s/aaaaaaaaaa/b/g; t b; b done
    : b;  s/bbbbbbbbbb/c/g; t c; b done
    : c;  s/cccccccccc/d/g; t d; b done
    : d;  s/dddddddddd/e/g; t e; b done
    : e;  s/eeeeeeeeee/f/g; t f; b done
    : f;  s/ffffffffff/g/g; t g; b done
    : g;  s/gggggggggg/h/g; t h; b done
    : h;  s/hhhhhhhhhh//g
    : done

    # convert back to numbers
    : loop
    /a/! s/[b-h]*/&0/
    s/aaaaaaaaa/9/
    s/aaaaaaaa/8/
    s/aaaaaaa/7/
    s/aaaaaa/6/
    s/aaaaa/5/
    s/aaaa/4/
    s/aaa/3/
    s/aa/2/
    s/a/1/

    # loop to do next digit
    y/bcdefgh/abcdefg/
    /[a-h]/ b loop
    ' 

------------------------------------------------------------------------------
Reverse characters in a line

  sed -e '
     # skip lines with lest than two characters
     /../! b

     # Embed newlines at both ends
     # then slowly meove markers toward middle
     :x
     s/\(\n.\)\(.*\)\(.\n\)/\3\2\1/
     tx

     # remove newline markers
     s/\n//g
     '

-------------------------------------------------------------------------------