Never been to CodeSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

Magic space on the current command line


# For how to set up magic space for Bash see: 
# - http://www.ukuug.org/events/linux2003/papers/bash_tips/#slide15
# - http://codesnippets.joyent.com/posts/show/1690


man bash 2>/dev/null | less -p 'magic-space'

man bash 2>/dev/null | less -p 'Event Designators'

man bash 2>/dev/null | less -p '\!#'    #  "The entire command line typed so far."


# accessing the current line typed so far


echo 1 2 3 4 5 "hello world" !#                [press space]

[ctrl-u]

echo 1 2 3 4 5 "hello world" !#:0

echo 1 2 3 4 5 "hello world" !#:3

echo 1 2 3 4 5 "hello world" !#:1-5

echo 1 2 3 4 5 "hello world" !#*


echo 1 2 3 4 5 "hello world" !#-
echo 1 2 3 4 5 "hello world" !#:-
echo 1 2 3 4 5 "hello world" !#:3
echo 1 2 3 4 5 "hello world" !#:-3
echo 1 2 3 4 5 "hello world" !#:^
echo 1 2 3 4 5 "hello world" !#:$

echo 1 2 3 4 5 !#:0:s/echo/HELLO/

echo 1 2 3 4 5 !#:1:s/1/ZZZZZZ/

echo 1 2 3 4 5 !#:1:s/T/ZZZZZZ/


echo 1 "211 1" 3 4 5 !#:gs/1/Z/

echo 1 "211 1" 3 4 5 !#:Gs/1/Z/


echo /path/to/file.txt !#:e



#----------------------------------------------------



# accessing the previous line

echo 1 2 3 4 5 "hello world"

# entire line
echo !!                  [press space]

[ctrl-u]

echo !!*
echo !!:1-


echo hello
echo world

echo !*
echo !-1*
echo !-2*

echo hello world
echo !:1-



# last argument
echo !$

# alternatives (no magic space)
#echo "${_}"    
# [esc-.]


echo 1 2 3 4 5 "hello world"

echo !!:0
echo !!:1-2
echo !-1:0
echo !-1:4-6
echo !*

Add Mac OS X menu bar items from the command line


locate *.menu

find -x /System/Library/CoreServices /Library/PreferencePanes /Applications  -name "*.menu"


open '/System/Library/CoreServices/Menu Extras/Eject.menu'
open '/System/Library/CoreServices/Menu Extras/CPU.menu'
open '/System/Library/CoreServices/Menu Extras/Fax.menu'
open '/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu'

Manage FadeText screensaver from the command line


# requires FadeText, http://allocsoft.com/fadetext/ (installed in ~/Library/Services & ~/Library/Screen\ Savers)
# requires PlistBuddy, http://codesnippets.joyent.com/posts/show/1484


# general screensaver functions

function screensaver() {
  /System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine &>/dev/null
   return 0
}


function screensaverprefs() {
   /usr/bin/open -a 'System Preferences' /System/Library/PreferencePanes/ScreenSaver.prefPane
   return 0
}



# cf. http://codesnippets.joyent.com/posts/show/2079

function change_screensaver() {

   declare IFS=$'\n' DIR1 DIR2 DIR3 indent index num saver

   DIR1='/Library/Screen Savers'
   DIR2='/System/Library/Screen Savers'
   DIR3="${HOME}/Library/Screen Savers"

   if [[ -n "${1}" ]]; then
      screensavers=( $( /usr/bin/find -x "$DIR1" "$DIR2" "$DIR3" -mindepth 1 -maxdepth 1 -iname "*${1}*saver" ) )
   else
      screensavers=( $( /usr/bin/find -x "$DIR1" "$DIR2" "$DIR3" -mindepth 1 -maxdepth 1 -iname "*saver" ) )
   fi


   if [[ ${#screensavers[@]} -eq 0 ]]; then

      printf "\n%s\n\n" 'No screen *saver found in:'
      indent=5
      printf "%+$[${#DIR1}+${indent}]s\n%+$[${#DIR2}+${indent}]s\n%+$[${#DIR3}+${indent}]s\n\n" "$DIR1" "$DIR2" "$DIR3"
      return 1

   elif [[ ${#screensavers[@]} -eq 1 ]]; then

      index=0

   elif [[ ${#screensavers[@]} -gt 1 ]]; then

      #printf "%s\n" "${screensavers[@]##*/}" | nl -s "    "   # print basename only

      echo
      for ((i=0; i < ${#screensavers[@]}; i++)); do 
         printf "\e[1m%+8s\e[m    %s\n" "$[ ${i} +1 ]:" "${screensavers[${i}]##*/}"   # print basename only
      done

      echo
      read -e -p $'\e[1mChoose one of the screen saver numbers above\e[m:  '  num
      echo

      # check if $num is a positive integer
      # check for leading zeros
      #if [[ "${num//[[:digit:]]/}" != "" ]] || [[ "${num#"${num%%[!0]*}"}" != "${num}" ]]; then
      if [[ "${num}" -lt 1 ]]; then
         echo 'Wrong input!'
         return 1
      fi

      index=$[ $num - 1 ]

      [[ ${index} -ge ${#screensavers[@]} ]] && echo 'Number too high!' && return 1

   fi

   saver="${screensavers[${index}]}"

   /usr/bin/defaults -currentHost write com.apple.screensaver modulePath -string "${saver}"

   echo; echo "${saver}"; echo

   saver="${saver##*/}"
   saver="${saver%.*}"
   /usr/bin/defaults -currentHost write com.apple.screensaver moduleName -string "${saver}"


   /bin/sleep 1

   /usr/bin/open /System/Library/Frameworks/ScreenSaver.framework/Versions/A/Resources/ScreenSaverEngine.app

   return 0

}



#---------------------------------------------------------------------------------------------------



# get MAC address used in "com.webbingtec.fadetext*.plist"
ifconfig en0 | sed -E -n -e 's/://g' -e '/ether/s/^[[:space:]]+ether[[:space:]]+(.+)/\1/p'


function savefadetext() {
   declare plistfile savedir text
   savedir="${HOME}/Library/FadeText"
   plistfile="$(/usr/bin/find -x ~/Library/Preferences/ByHost -name "com.webbingtec.fadetext*.plist" | /usr/bin/tail -n 1)"
   [[ ! -f "${plistfile}" ]] && echo "No such file: ${plistfile}" && return 1
   /bin/mkdir -p "${savedir}"
   text="$( /usr/libexec/PlistBuddy -c 'Print :Content' "${plistfile}" )"
   if [[ -n "${1}" ]]; then
      #printf "%s\n" "${text}" > "${savedir}/fadetext-${1}"
      printf "%s\n" "${text}" > "${savedir}/fadetext-${1}-$(/bin/date +%Y-%m-%d--%H.%M.%S)"
   else
      printf "%s\n" "${text}" > "${savedir}/fadetext-$(/bin/date +%Y-%m-%d--%H.%M.%S)"
   fi
   return 0
}


function clearfadetext() {
   declare plistfile
   plistfile="$(/usr/bin/find -x ~/Library/Preferences/ByHost -name "com.webbingtec.fadetext*.plist" | /usr/bin/tail -n 1)"
   [[ ! -f "${plistfile}" ]] && echo "No such file: ${plistfile}" && return 1
   /usr/libexec/PlistBuddy -c 'Set :Content ""' "${plistfile}"
   return 0
}


function addfadetext() {
   #unset -v i ar text
   declare -a ar
   declare -i i=-1
   declare IFS=$'\n' plistfile text
   plistfile="$(/usr/bin/find -x ~/Library/Preferences/ByHost -name "com.webbingtec.fadetext*.plist" | /usr/bin/tail -n 1)"
   [[ ! -f "${plistfile}" ]] && echo "No such file: ${plistfile}" && return 1
   text="$( /usr/libexec/PlistBuddy -c 'Print :Content' "${plistfile}" )"
   while read -e -d $'\n' line; do let i++; ar[${i}]="${line%"${line##*[![:space:]]}"}"$' \n'; done   # add $' \n' to every line; -e enables readline
   printf "%s\n" "${ar[@]}" >> ~/.bash_history
   history -n
   if [[ -n "${text}" ]]; then
      text="${text}"$'\n\n'"$(printf "%s" "${ar[@]}")"
   else
      text="$(printf "%s" "${ar[@]}")"
   fi
   # escape single quotes
   text="${text//\'/\'}"$'\n'
   /usr/libexec/PlistBuddy -c "Set :Content '${text}'" "${plistfile}"
   /bin/sleep 1
   change_screensaver FadeText
   return 0
}


# alternative to addfadetext
function fadetext() {
   /usr/bin/open ~/Library/Services/FadeTextService.app
   return 0
}


function newfadetext() {
   savefadetext
   clearfadetext
   addfadetext
   #/bin/sleep 1
   #change_screensaver FadeText
   return 0
}



function loadfadetext() {
   savefadetext
   clearfadetext
   unset -v array
   declare -a array
   declare -i i=0
   declare IFS=$'\n' plistfile text
   plistfile="$(/usr/bin/find -x ~/Library/Preferences/ByHost -name "com.webbingtec.fadetext*.plist" | /usr/bin/tail -n 1)"
   [[ ! -f "${1}" ]] && echo "No such file: ${1}" && return 1
   while read -d $'\n' line; do
      array[i++]="${line}"
   done < <( /bin/ed -s "${1}" <<< $',p' 2>/dev/null)   # also reads last line without final \n
   text="$(printf "%s\n" "${array[@]}")"
   # escape single quotes
   text="${text//\'/\'}"$'\n'
   /usr/libexec/PlistBuddy -c "Set :Content '${text}'" "${plistfile}"
   /bin/sleep 1
   change_screensaver FadeText
   return 0
}


# use [ctrl-d] to modify FadeText
# use [ctrl-c] to quit without modifying FadeText
# backup directory: ~/Library/FadeText

screensaverprefs       # activate FadeText screensaver

addfadetext

savefadetext testname

newfadetext

loadfadetext /path/to/file.txt

clearfadetext



#-------------------------------------------------------------------------------------



# alternative *fadetext versions using: defaults -currentHost ...

# alternative to using: PlistBuddy & find -x .../ByHost -name "com.webbingtec.fadetext*.plist"
defaults -currentHost read | grep -i saver
defaults -currentHost read com.webbingtec.fadetext
defaults -currentHost read com.webbingtec.fadetext Content
defaults -currentHost write com.webbingtec.fadetext Content -string 'new message'
screensaver


function savefadetext() {
   declare savedir text
   savedir="${HOME}/Library/FadeText"
   /bin/mkdir -p "${savedir}"
   text="$( /usr/bin/defaults -currentHost read com.webbingtec.fadetext Content )"
   if [[ -n "${1}" ]]; then
      #printf "%s\n" "${text}" > "${savedir}/fadetext-${1}"
      printf "%s\n" "${text}" > "${savedir}/fadetext-${1}-$(/bin/date +%Y-%m-%d--%H.%M.%S)"
   else
      printf "%s\n" "${text}" > "${savedir}/fadetext-$(/bin/date +%Y-%m-%d--%H.%M.%S)"
   fi
   return 0
}


function clearfadetext() {
   /usr/bin/defaults -currentHost write com.webbingtec.fadetext Content -string ""
   return 0
}


function addfadetext() {
   #unset -v i ar text
   declare -a ar
   declare -i i=-1
   declare IFS=$'\n' plistfile text
   text="$( /usr/bin/defaults -currentHost read com.webbingtec.fadetext Content )"
   while read -e -d $'\n' line; do let i++; ar[${i}]="${line%"${line##*[![:space:]]}"}"$' \n'; done   # add $' \n' to every line; -e enables readline
   printf "%s\n" "${ar[@]}" >> ~/.bash_history
   history -n
   if [[ -n "${text}" ]]; then
      text="${text}"$'\n\n'"$(printf "%s" "${ar[@]}")"
   else
      text="$(printf "%s" "${ar[@]}")"
   fi
   /usr/bin/defaults -currentHost write com.webbingtec.fadetext Content -string "${text}"
   /bin/sleep 1
   change_screensaver FadeText
   #/usr/bin/open /System/Library/Frameworks/ScreenSaver.framework/Versions/A/Resources/ScreenSaverEngine.app
   return 0
}


# alternative to addfadetext
function fadetext() {
   /usr/bin/open ~/Library/Services/FadeTextService.app
   return 0
}


function newfadetext() {
   savefadetext
   clearfadetext
   addfadetext
   return 0
}


function loadfadetext() {
   savefadetext
   clearfadetext
   unset -v array
   declare -a array
   declare -i i=0
   declare IFS=$'\n' plistfile text
   while read -d $'\n' line; do
      array[i++]="${line}"
   done < <( /bin/ed -s "${1}" <<< $',p' 2>/dev/null)   # also reads last line without final \n
   text="$(printf "%s\n" "${array[@]}")"
   /usr/bin/defaults -currentHost write com.webbingtec.fadetext Content -string "${text}"
   /bin/sleep 1
   change_screensaver FadeText
   #/usr/bin/open /System/Library/Frameworks/ScreenSaver.framework/Versions/A/Resources/ScreenSaverEngine.app
   return 0
}

cmdparser - parse command line arguments with Bash built-in regex matching

Author: jv
License: The MIT License, Copyright (c) 2009 jv
Description: a basic regex-based command line parser for use in Bash scripts (Mac OS X); uses Bash built-in regex matching via the comparison operator "=~" and the array variable BASH_REMATCH; an alternative to the built-in getopts command (cf. help getopts); use at your own risk
Bash version: GNU bash, version 3.2.25(1)-release
Usage: /path/to/script_with_cmdparser -a -b -c -f file

Related links:
- cmdparser - parse command line arguments (links)
- Process positional parameters non-destructively in Bash
- Update your Bash shell via MacPorts

Version 1: modifies (the number of) command line arguments ($# and $@).

#!/opt/local/bin/bash

# bash --version
# GNU bash, version 3.2.25(1)-release

# This version of cmdparser uses Bash built-in regular expression matching and 
# modifies (the number of) command line arguments ($# and $@).


export PATH=/usr/bin:/bin:/usr/sbin:/sbin
export IFS=$' \t\n'

# create a fake command line
#set -- -abcc -c -zz -flag1="" -flag2=arg -flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' -flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces  / * + ` \ ! ' -flag9 ~/Desktop/*.txt filename1 filename2 filename3

set -- -abcc -c -zz -flag1="" -flag2=arg -flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' -flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ ! ' -flag9 '~/Desktop/*.txt' filename1 filename2 filename3


printf "%s\n" "$@" | nl
#printf "%s" "$@"$'\n' | nl
#printf "%s" "${@/%/ }" | nl


: <<-'COMMENT'

# copy & paste examples for the command line

echo "filename1" "filename2" "filename3" | ~/Desktop/cmdparser.txt -abcc -c -zz -flag1 arg -flag2=arg --flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' --flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ ! ' -flag9 ~/Desktop/*.txt -

echo "filename1" "filename2" "filename3" | ~/Desktop/cmdparser.txt -abcc -c -zz -flag1 arg -flag2=arg --flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' --flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ ! ' -flag9 '~/Desktop/*.txt' -

COMMENT



# cmdparser

usage="usage: $(/usr/bin/basename "$0") [-a] [-b] [-c] [-cc] [-zz] [-flag1 arg] [-flag2 'arg1 arg2 ...'] [-flag3=arg] [-flag4=\"arg1 arg2\"] ..."


# Note: names of flags and switches may not contain the characters "-", "." or "=".

# define the names of flags as a regular expression
# flags are command line options that require arguments

flags="(flag1|flag2|flag3|flag4|flag5|flag6|flag7|flag8|flag9)"


# define the names of switches as a regular expression
# Switches are command line options that do not take arguments.
# Make sure multi-char switches precede single-char switches in the regular expression.
# Note that the regular expression contains neither the special read-from-stdin switch "-" 
# nor the special end-of-options switch "--".

switches="(cc|zz|a|b|c)"  


declare flag1 flag2 flag3 flag4 flag5 flag6 flag7 flag8 flag9                # flags
declare -i a=0 b=0 c=0 cc=0 zz=0                                            # switches
                         
declare argstr argvar argvar_escaped char flagvar optstr piped pipedstr       # script variables
declare -i optid pipedvar

# piped="piped" will be used for variable creation 
# example: piped="piped"; pipedstr="piped arg"; eval $piped='"$(echo "$pipedstr")"'; echo "$piped"

piped="piped"

# default value is set to "no pipe"
pipedvar=0
pipedstr=""

# if /dev/stdin has a size greater than zero ...
if [[ -s /dev/stdin ]]; then pipedstr="$(</dev/stdin)"; fi 

if [[ $# -eq 0 ]] && [[ -z "$pipedstr" ]]; then
  printf "\n%s\n\n%s\n\n" 'No arguments specified!' "$usage" 1>&2
  exit 1
fi 

if [[ $# -eq 0 ]] && [[ -n "$pipedstr" ]]; then
  eval $piped='"${pipedstr}"'  
  pipedvar=1
fi 

# if there are command line arguments ...
# Note that $pipedvar may still be set to 1 below if the special read-from-stdin switch "-" is given.

if [[ $pipedvar -eq 0 ]]; then

   optstr=" "  
   optid=0

   while [[ -n "$optstr" ]]; do     

      # try to extract valid flags or switches from positional parameter $1
      # $1 gets shifted afterwards (cf. help shift)


      [[ "$1" =~ ^--?${flags}$ ]]
      optstr="${BASH_REMATCH[0]}"


      if [[ -n "$optstr" ]]; then optid=1; fi

      if [[ -z "$optstr" ]]; then optid=2;  [[ "$1" =~ ^--?${switches}$ ]]; optstr="${BASH_REMATCH[0]}"; fi

      if [[ -z "$optstr" ]]; then optid=3; [[ "$1" =~ ^--?${switches}+$ ]]; optstr="${BASH_REMATCH[0]}"; fi

      if [[ -z "$optstr" ]]; then optid=4; [[ "$1" =~ ^--?(${flags}=.*|${flags}[^[:space:]]+)$ ]]; optstr="${BASH_REMATCH[0]}"; fi


      if [[ -z "$optstr" ]]; then  
         if [[ "$1" = "-" ]] && [[ "$@" = "-" ]]; then  
            optid=5
            optstr="-" 
         fi
      fi


      if [[ -z "$optstr" ]]; then

         # append a space to each command line argument
         argstr="$(printf "%s" "${@/%/ }")"

         [[ "$argstr" =~ [[:space:]]--?(${flags}|${switches}) ]]

         if [[ -n "${BASH_REMATCH[0]}" ]]; then 
            printf "\n%s\x21\n\n%s\n\n%s\n\n" "Undefined non-option string: ${1:0:1000} is followed by a legal flag or switch" "${BASH_REMATCH[0]}" "$usage" 1>&2
            exit 1
         fi

      fi


      if [[ "$1" = "--" ]]; then shift; break; fi     # -- marks end of options

      if [[ -z "$optstr" ]]; then break; fi     # no further flags or switches to process


      # flag followed by space (example: -f file)
      if [[ $optid -eq 1 ]]; then 

         if [[ -z "$2" ]]; then
            printf "%s\n%s\n" "no argument given to flag: ${1}" "$usage" 1>&2
            exit 1
         fi 

         flagvar="${1#"${1%%[!-]*}"}"     # remove leading - or --
         argvar="$2"
         eval $flagvar='"${argvar}"'
         shift 2     # shift positional parameters $1 & $2 (that is, a flag plus its argument)
         continue


      # single switch (example: -a)
      elif [[ $optid -eq 2 ]]; then
         flagvar="${1#"${1%%[!-]*}"}"
         eval $flagvar='"1"'
         shift
         continue
  

      # combined switch (example: -abcc)
      elif [[ $optid -eq 3 ]]; then

         flagvar="${1#"${1%%[!-]*}"}"

         while [[ -n "$flagvar" ]]; do

            [[ "$flagvar" =~ ^${switches}.*$ ]]
            char="${BASH_REMATCH[1]}"

            eval $char='"1"'

            [[ "$flagvar" =~ ^${switches}(.*)$ ]]
            flagvar="${BASH_REMATCH[2]}"

         done

         shift
         continue


      # flag without following space (example: -ffile)
      elif [[ $optid -eq 4 ]]; then 

         [[ "${1#"${1%%[!-]*}"}" =~ ^${flags}=?(.*)$ ]]
         argvar="${BASH_REMATCH[2]}"

         [[ "${1#"${1%%[!-]*}"}" =~ ^${flags}=?.*$ ]]
         flagvar="${BASH_REMATCH[1]}"

         # alternative
         #[[ "${1}" =~ ^--?${flags}=?(.*)$ ]]
         #argvar="${BASH_REMATCH[2]}"

         #[[ "${1}" =~ ^--?${flags}=?.*$ ]]
         #flagvar="${BASH_REMATCH[1]}"

         eval $flagvar='"${argvar}"'
         shift
         continue


      # the special read-from-stdin switch "-"
      elif [[ $optid -eq 5 ]]; then 
         pipedvar=1
         eval $piped='"${pipedstr}"'
         shift
         break

      fi

      # remove positional parameter $1 from "$@"
      shift

   done

fi   # if [[$pipedvar -eq 0 ]]; then ...


echo 

printf "%s\t%s\n" "a:" "${a}"
printf "%s\t%s\n" "b:" "${b}"
printf "%s\t%s\n" "c:" "${c}"
printf "%s\t%s\n" "cc:" "${cc}"
printf "%s\t%s\n" "zz:" "${zz}"
printf "%s\t%s\n" "flag1:" "${flag1}"
printf "%s\t%s\n" "flag2:" "${flag2}"
printf "%s\t%s\n" "flag3:" "${flag3}"
printf "%s\t%s\n" "flag4:" "${flag4}"
printf "%s\t%s\n" "flag5:" "${flag5}"
printf "%s\t%s\n" "flag6:" "${flag6}"
printf "%s\t%s\n" "flag7:" "${flag7}"
printf "%s\t%s\n" "flag8:" "${flag8}"
printf "%s\t%s\n" "flag9:" "${flag9}"

echo


if [[ $pipedvar -eq 1 ]] && [[ -z "$@" ]]; then 
   echo "remaining string-piped: ${piped}"
else 
   echo "remaining string: ${@}"
fi

echo

if [[ $flag9 == '~/Desktop/*.txt' ]]; then printf "%s\n" ~/Desktop/*.txt | nl; fi

echo

exit 0




Version 2: does not modify (the number of) command line arguments ($# and $@).

#!/opt/local/bin/bash

# bash --version
# GNU bash, version 3.2.25(1)-release

# This version of cmdparser uses Bash builtin regex matching and 
# does not modify (the number of) command line arguments ($# and $@).


# create a fake command line
set -- -abcc -c -zz -flag1="" -flag2=arg$'\n'plus_newline -flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' -flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ !' -flag9 ~/Desktop/*.txt filename1 filename2 filename3

#set -- -abcc -c -zz -flag1="" -flag2=arg$'\n'plus_newline -flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' -flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ !' -flag9 '~/Desktop/*.txt' filename1 filename2 filename3


printf "%s\n" "$@" | nl
#printf "%s" "$@"$'\n' | nl
#printf "%s" "${@/%/ }" | nl


: <<-'COMMENT'

# copy & paste examples

echo "filename1" "filename2" "filename3" | ~/Downloads/Mac-OS-X-bash-scripts/bash-cmdparser/cmdparser-non-destructive-1.txt -abcc -c -zz -flag1 arg -flag2=arg$'\n'plus_newline --flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' --flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ !' -flag9 ~/Desktop/*.txt -

echo "filename1" "filename2" "filename3" | ~/Downloads/Mac-OS-X-bash-scripts/bash-cmdparser/cmdparser-non-destructive-1.txt -abcc -c -zz -flag1 arg -flag2=arg$'\n'plus_newline --flag3="arg" -flag4='arg1=*,arg2=?,arg3=!' -flag5 '(arg1|arg2|arg3)' -flag6 'arg1=ag,arg2=bg,arg3=cg' --flag7 An\ argument\ with\ spaces\! -flag8='Yet another argument with spaces / * + ` \ !' -flag9 '~/Desktop/*.txt' -

COMMENT


echo

echo "Number of positional parameters: ${#}"

echo


# cmdparser

export PATH=/usr/bin:/bin:/usr/sbin:/sbin
export IFS=$' \t\n'


# Note: names of flags and switches may not contain the characters "-", "." or "=".

# define the names of flags as a regular expression
# flags are command line options that require arguments

flags="(flag1|flag2|flag3|flag4|flag5|flag6|flag7|flag8|flag9)"


# define the names of switches as a regular expression
# Switches are command line options that do not take arguments.
# Make sure multi-char switches precede single-char switches in the regular expression.
# Note that the regular expression contains neither the special read-from-stdin switch "-" 
# nor the special end-of-options switch "--".

switches="(cc|zz|a|b|c)"  


usage="usage: $(/usr/bin/basename "$0") [-a] [-b] [-c] [-cc] [-zz] [-flag1 arg] [-flag2 'arg1 arg2 ...'] [-flag3=arg] [-flag4=\"arg1 arg2\"] ..."

declare flag1 flag2 flag3 flag4 flag5 flag6 flag7 flag8 flag9                # flags
declare -i a=0 b=0 c=0 cc=0 zz=0                                            # switches
                         
declare argn argstr argvar argvar_escaped char flagvar optstr piped pipedstr       # script variables
declare -i optid pipedvar
declare -a argarslice

# piped="piped" will be used for variable creation 
# example: piped="piped"; pipedstr="piped arg"; eval $piped='"$(echo "$pipedstr")"'; echo "$piped"

piped="piped"

# default value is set to "no pipe"
pipedvar=0
pipedstr=""

# if /dev/stdin has a size greater than zero ...
if [[ -s /dev/stdin ]]; then pipedstr="$(</dev/stdin)"; fi 

if [[ $# -eq 0 ]] && [[ -z "$pipedstr" ]]; then
  printf "\n%s\n\n%s\n\n" 'No arguments specified!' "$usage" 1>&2
  exit 1
fi 

if [[ $# -eq 0 ]] && [[ -n "$pipedstr" ]]; then
  eval $piped='"${pipedstr}"'  
  pipedvar=1
fi 

# if there are command line arguments ...
# Note that $pipedvar may still be set to 1 below if the special read-from-stdin switch "-" is given

if [[ $pipedvar -eq 0 ]]; then

   optstr=" "  
   optid=0


   # processing one positional parameter at a time without modifying $# or $@
   # Process positional parameters non-destructively in Bash, http://codesnippets.joyent.com/posts/show/1706

   for (( i=1; i <= $#; i++ )); do 


      argn="${@:${i}:1}"     # current positional parameter
                             # "${@:(${i}+1):1}": the positional parameter following the current one
                             # "${@:${i}}": all positional parameters starting with the current one


      [[ "$argn" =~ ^--?${flags}$ ]]
      optstr="${BASH_REMATCH[0]}"


      if [[ -n "$optstr" ]]; then optid=1; fi

      if [[ -z "$optstr" ]]; then optid=2;  [[ "$argn" =~ ^--?${switches}$ ]]; optstr="${BASH_REMATCH[0]}"; fi

      if [[ -z "$optstr" ]]; then optid=3; [[ "$argn" =~ ^--?${switches}+$ ]]; optstr="${BASH_REMATCH[0]}"; fi

      if [[ -z "$optstr" ]]; then optid=4; [[ "$argn" =~ ^--?(${flags}=.*|${flags}[^[:space:]]+)$ ]]; optstr="${BASH_REMATCH[0]}"; fi


      if [[ -z "$optstr" ]]; then  
         if [[ "${argn}" = "-" ]] && [[ "${@:${i}}" = "-" ]]; then
            optid=5
            optstr="-" 
         fi
      fi


      if [[ -z "$optstr" ]]; then

         # append a space to each command line argument
         argarslice=( "${@:${i}}" )
         argstr="$(printf "%s" "${argarslice[@]/%/ }")"

         [[ "$argstr" =~ [[:space:]]--?(${flags}|${switches}) ]]

         if [[ -n "${BASH_REMATCH[0]}" ]]; then 
            printf "\n%s\x21\n\n%s\n\n%s\n\n" "Undefined non-option string: ${argn:0:1000} is followed by a legal flag or switch" "${BASH_REMATCH[0]}" "$usage" 1>&2
            exit 1
         fi

      fi


      if [[ "${argn}" = "--" ]]; then break; fi     # -- marks end of options

      if [[ -z "$optstr" ]]; then break; fi     # no further flags or switches to process


      # flag followed by space (example: -f file)
      if [[ $optid -eq 1 ]]; then 

         if [[ -z "${@:(${i}+1):1}" ]]; then
            printf "%s\n%s\n" "no argument given to flag: ${argn}" "$usage" 1>&2
            exit 1
         fi 

         flagvar="${argn#"${argn%%[!-]*}"}"     # remove leading dashes
         argvar="${@:(${i}+1):1}"
         eval $flagvar='"${argvar}"'
         let "i += 1"     # skip argument of current flag in next for loop
         continue

      # single switch (example: -a)
      elif [[ $optid -eq 2 ]]; then
         flagvar="${argn#"${argn%%[!-]*}"}"
         eval $flagvar='"1"'
         continue
  
      # combined switch (example: -abcc)
      elif [[ $optid -eq 3 ]]; then
         flagvar="${argn#"${argn%%[!-]*}"}"
         while [[ -n "$flagvar" ]]; do

            [[ "$flagvar" =~ ^${switches}.*$ ]]
            char="${BASH_REMATCH[1]}"

            eval $char='"1"'

            [[ "$flagvar" =~ ^${switches}(.*)$ ]]
            flagvar="${BASH_REMATCH[2]}"

         done
         continue


      # flag without following space (example: -ffile)
      elif [[ $optid -eq 4 ]]; then 

         [[ "${argn#"${argn%%[!-]*}"}" =~ ^${flags}=?(.*)$ ]]
         argvar="${BASH_REMATCH[2]}"

         [[ "${argn#"${argn%%[!-]*}"}" =~ ^${flags}=?.*$ ]]
         flagvar="${BASH_REMATCH[1]}"

         # alternative
         #[[ "${argn}" =~ ^--?${flags}=?(.*)$ ]]
         #argvar="${BASH_REMATCH[2]}"

         #[[ "${argn}" =~ ^--?${flags}=?.*$ ]]
         #flagvar="${BASH_REMATCH[1]}"


         eval $flagvar='"${argvar}"'
         continue


      # the special read-from-stdin switch "-"
      elif [[ $optid -eq 5 ]]; then 
         pipedvar=1
         eval $piped='"${pipedstr}"'
         break

      fi

   done   # for loop

fi   # if [[$pipedvar -eq 0 ]]; then ...


echo 

printf "%s\t%s\n" "a:" "${a}"
printf "%s\t%s\n" "b:" "${b}"
printf "%s\t%s\n" "c:" "${c}"
printf "%s\t%s\n" "cc:" "${cc}"
printf "%s\t%s\n" "zz:" "${zz}"
printf "%s\t%s\n" "flag1:" "${flag1}"
printf "%s\t%s\n" "flag2:" "${flag2}"
printf "%s\t%s\n" "flag3:" "${flag3}"
printf "%s\t%s\n" "flag4:" "${flag4}"
printf "%s\t%s\n" "flag5:" "${flag5}"
printf "%s\t%s\n" "flag6:" "${flag6}"
printf "%s\t%s\n" "flag7:" "${flag7}"
printf "%s\t%s\n" "flag8:" "${flag8}"
printf "%s\t%s\n" "flag9:" "${flag9}"

echo


if [[ $pipedvar -eq 1 ]] && [[ -z "$@" ]]; then 
   echo "remaining string-piped: ${piped}"
else 
   echo "remaining string: ${@}"
fi

echo

echo "Number of positional parameters: ${#}"

echo

if [[ $flag9 == '~/Desktop/*.txt' ]]; then printf "%s\n" ~/Desktop/*.txt | nl; fi

#if [[ $flag9 == '~/Desktop/*.txt' ]]; then printf "%s\n" ${flag9} | nl; fi

echo

exit 0



sed - print n lines after match

lines=$'line1\nline2\nline3\nline4\nline5\n'


# print n lines after match if there are n lines, but do not print the matched line itself
echo -n "${lines}" | sed -n '/line2/{n;p;}'
echo -n "${lines}" | sed -n '/line2/{n;{N;p;};}'
echo -n "${lines}" | sed -n '/line2/{n;{N;N;p;};}'
echo -n "${lines}" | sed -n '/line2/{n;{N;N;N;p;};}'


# print the matching line and n lines after the match if there are n lines
echo -n "${lines}" | sed -n '/line2/{N;p;}'
echo -n "${lines}" | sed -n '/line2/{N;N;p;}'
echo -n "${lines}" | sed -n '/line2/{N;N;N;p;}'
echo -n "${lines}" | sed -n '/line2/{N;N;N;N;p;}'


# print the matching line and n lines after the match (using grep)
echo -n "${lines}" | grep -A 1 'line2'
echo -n "${lines}" | grep -A 2 'line2'
echo -n "${lines}" | grep -A 3 'line2'
echo -n "${lines}" | grep -A 4 'line2'
echo -n "${lines}" | grep -A 10 'line2'

Read file into array in Bash


# cf. "How can I read a file (data stream, variable) line-by-line?", 
# http://wooledge.org:8000/BashFAQ/001

man bash 2>/dev/null | less -p '\$\(< file\)'

declare -a lines
OIFS="$IFS"
IFS=$'\n'
set -f   # cf. help set
lines=( $(< "/private/etc/passwd" ) )
set +f
IFS="$OIFS"

echo "${#lines[@]}"
printf "%s\n" "${lines[@]}" | nl

for ((i=0; i < "${#lines[@]}"; i++)); do 
   echo "${lines[${i}]}"
done


#------------------------------------------------------------


# read file into array

# version 1

man bash 2>/dev/null | less -p '\$\(< file\)'
OIFS="$IFS"
IFS=$'\n'
set -f    # disable file name generation (globbing)
lines=( $(< "/private/etc/passwd" ) )
set +f
IFS="$OIFS"
printf "%s\n" "${lines[@]}" | nl


# version 2

# preserve empty lines: line =~ ^\n$
/usr/bin/jot -b 'Sample Text' 10 > ~/Desktop/test
unset -v array
declare -a array
declare -i i=0
IFS=$'\777'
IFS=$'\n'
while read -d $'\n' line; do
   #array+="${line}"  # influenced by IFS
   array[i++]="${line}"
#done < <( cat ~/Desktop/test)
done < <( /bin/ed -s ~/Desktop/test <<< $',p' 2>/dev/null)   # also reads last line without final \n
echo "${array[@]}"
echo "${#array[@]}"


# version 3

bash --version     #  GNU bash, version 4.0.10(1)-release

# use the builtin mapfile to read a file into an array (only Bash 4)
# help mapfile
# http://bash-hackers.org/wiki/doku.php/commands/builtin/mapfile

IFS=$'\777'
/usr/bin/jot -b 'Sample Text' 10 > ~/Desktop/test
mapfile < ~/Desktop/test
mapfile -t < ~/Desktop/test
mapfile -t < ~/Desktop/test myarray
printf "%s\n" "${MAPFILE[@]}"
printf "%s\n" "${MAPFILE[2]}"
for ((i=0; i < "${#MAPFILE[@]}"; i++)); do printf "%s\n" "${MAPFILE[${i}]}"; done
for ((i=0; i < "${#MAPFILE[@]}"; i++)); do printf "%s\n" "${i}:  ${MAPFILE[${i}]}"; done

for ((i=0; i < "${#myarray[@]}"; i++)); do printf "%s\n" "${myarray[${i}]}"; done
for ((i=0; i < "${#myarray[@]}"; i++)); do printf "%s\n" "${i}:  ${myarray[${i}]}"; done

IFS=$' \t\n'

Process positional parameters non-destructively in Bash

Extract positional parameters without modifying (the number of) command line arguments ($# and $@).

# See:
# - http://tldp.org/LDP/abs/html/string-manipulation.html#AEN5117
# - http://tldp.org/LDP/abs/html/internalvariables.html#POSPARAMREF
# - http://tldp.org/LDP/abs/html/internalvariables.html#IFSREF
# - http://tldp.org/LDP/abs/html/parameter-substitution.html#PARAMSUBREF
# - cmdparser, http://codesnippets.joyent.com/posts/show/1697

export IFS=$' \t\n'

# create a fake command line
set -- "First one" "second" "third:one" "" "Fifth: :one"
set -- "First one" "second" "third:"$'\n'"one" "" "Fifth: :one"

echo $#                             # number of arguments

printf "%s\n" "${@}"                # all arguments         

printf "%s\n" "${1}"                # first argument          
printf "%s\n" "${3}"                # third argument
printf "%s\n" "${5}"                # last argument

printf "%s\n" "${@:1}"              # all arguments starting with the first
printf "%s\n" "${@:2}"              # all arguments starting with the second
printf "%s\n" "${@:3}"              # all arguments starting with the third

printf "%s\n" "${@:(-$#):1}"        # first argument          
printf "%s\n" "${@:$#:1}"           # last argument          
printf "%s\n" "${!#}"               # last argument

printf "%s\n" "${@:1:1}"            # first argument
printf "%s\n" "${@:3:1}"            # third argument
printf "%s\n" "${@:5:1}"            # fifth argument
printf "%s\n" "${@:(-1):1}"         # last argument
printf "%s\n" "${@:(-2):1}"         # second-to-last argument



# process one positional parameter at a time without modifying $# or $@
for (( i=1; i <= $#; i++ )); do printf "%s\n" "${@:${i}:1}"; done

echo $#    # 5


# $# and $@ get modified
for (( i=1; i <= $#; i++ )); do echo $i; printf "%s\n" "$1"; shift; done

echo $#   # 2


set -- "First one" "second" "third:"$'\n'"one" "" "Fifth: :one"

# $# and $@ get modified
while [[ $# -gt 0 ]]; do printf "%s\n" "$1"; shift; done

echo $#   # 0

Counting lines

# create a test file
testfile="${HOME}/Desktop/testfile.txt"
jot -b 'sample text' 10 | cat -n > "$testfile"
printf "%s\n" >> "$testfile"                                 # add an empty line
printf "%s\n\r\n\r\n\r\r\n" "sample text" >> "$testfile"     # add lines with '\r\n' as line separators 
printf "%s" "sample text" >> "$testfile"                     # add a last line without a terminating '\n'       

open -e "$testfile"

function odcfile() {
/usr/bin/od -A n -c < "$@" | /usr/bin/sed -E -e 's/^[[:space:]]{11}//' \
       -e s/[[:space:]]{4}/$'\001'/g \
       -e 's/[[:space:]]+//g' | \
       /usr/bin/tr -d '\n' | /usr/bin/tr '\001' ' ' | \
       /usr/bin/sed -e s/\\\\n/$'\\\\\\n\\\n'/g 

return 0
}

odcfile "$testfile"



# wc -l
wc -l < "$testfile"     # returns the number of '\n' characters

# ed 
ed -s "$testfile" <<< '='     # all lines

# cat
cat -n "$testfile" | awk 'END {print $1}'   # all lines


# grep
grep -c $'\n' "$testfile"                 # all lines
grep -c '^.*$' "$testfile"                # all lines
#grep -c $'\000' "$testfile"
grep -c $'\r$' "$testfile"                # all lines ending with \r\n
grep -c '^[[:space:]]*$' "$testfile"      # all blank lines
grep -cv '^[[:space:]]*$' "$testfile"     # all non-blank lines


# sed
sed -n '$=' "$testfile"                          # all lines
sed -n /$'\r'$/= "$testfile" | wc -l             # all lines ending with \r\n
sed -n '/^[[:space:]]*$/=' "$testfile" | wc -l   # all blank lines
sed -n '/[^[:space:]]/=' "$testfile" | wc -l     # all non-blank lines


# awk
awk 'END {print NR}' "$testfile"                           # all lines
awk '{x++} END {print x}' "$testfile"                      # all lines
awk '/^.*$/ {++x} END {print x}' "$testfile"               # all lines
awk '/\r$/ {++x} END {print x}' "$testfile"                # all lines ending with \r\n
awk '/^[[:space:]]*$/ {++x} END {print x}' "$testfile"     # all blank lines
awk '/[^[:space:]]/ {++x} END {print x}' "$testfile"       # all non-blank lines


# nl
nl "$testfile" | awk 'END {print $1}'
nl -b a "$testfile" | awk 'END {print $1}'   # including empty lines


#---------------------------------------------


# counting the lines of files in a directory

DIR=/path/to/dir

find "$DIR" -type f -name "*.txt" -print0 | xargs -0 wc -l

find "$DIR" -type f -name "*.txt" -print0 | xargs -0 sed -n '$='

find "$DIR" -type f -name "*.txt" -print0 | xargs -0 awk 'END {print NR}'
find "$DIR" -type f -name "*.txt" -print0 | xargs -0 awk '{x++} END {print x}'
find "$DIR" -type f -name "*.txt" -print0 | xargs -0 awk '/\r$/ {++x} END {print x}'
find "$DIR" -type f -name "*.txt" -print0 | xargs -0 awk '/^[[:space:]]*$/ {++x} END {print x}'
find "$DIR" -type f -name "*.txt" -print0 | xargs -0 awk '/[^[:space:]]/ {++x} END {print x}'


# requires Mac OS X 10.5 or port info findutils (/opt/local/bin/gfind)
find . -type f -name '*.txt' -exec sed -n '$=' '{}' + 2>/dev/null | awk '{ total+=$1 }END{print total}'
find . -type f -name '*.txt' -exec awk 'END {print NR}' '{}' + 2>/dev/null | awk '{ total+=$1 }END{print total}'



# rather slow, but without the "Argument list too long" issue: /usr/sbin/sysctl kern.argmax
# cf. http://www.onlamp.com/pub/a/bsd/2002/03/14/FreeBSD_Basics.html

declare -i linecnt=0
while read -d $'\0' file; do
   #linecnt=$((${linecnt} + $(/usr/bin/sed -n '$=' "${file}")))
   let "linecnt += $(/usr/bin/sed -n '$=' "${file}")"   # cf. help let
done < <(/usr/bin/find "$DIR" -type f -name "*.txt" -print0)

echo $linecnt


Counting lines in pure C:

/*

countlines -- count lines of files in given directories

compile with: 

gcc -std=c99 -Wall -Wextra -pedantic -O3 -o countlines countlines.c

Usage:

./countlines -h
./countlines ~/Desktop 2>/dev/null
./countlines -v ~/Desktop 2>/dev/null
./countlines -s '.c' ~/Desktop
./countlines -v -s '.m' ~/Desktop
./countlines /private/etc/passwd


For how to implement recursive directory scanning please see man 3 fts and:
   "fts(3) or Avoiding to Reinvent the Wheel",
   http://keramida.wordpress.com/2009/07/05/fts3-or-avoiding-to-reinvent-the-wheel/

*/


#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
#include <unistd.h>      // getopt


static int  ptree(char * const argv[], const char *suffix, int verbose);

static void usage(void)
{

   static const char *usageinfo[] = { 
      "countlines -- count lines of files in given directories", 
      "Usage:", 
      "countlines [-hv] [-s suffix] [ [dir1] [dir2] ...]",
      "-h: help",
      "-s: suffix",
      "-v: verbose",
      "Note:",
      "- Files named '.' or '..' get scanned.",
      "- File search will not descend into directories that have a different device number than the file from which the descent began.",
      "- fts_options: FTS_COMFOLLOW | FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT  (see man 3 fts)"
   };


   fprintf(stderr, 

      "\n%s\n\n"
      "%s\n\n"
      "\t%s\n\n"
      "\t%s\n\n"
      "\t%s\n\n"
      "\t%s\n\n"
      "\n%s\n\n"
      "\t%s\n\n"
      "\t%s\n\n"
      "\t%s\n\n", 

      usageinfo[0], usageinfo[1], usageinfo[2], usageinfo[3], usageinfo[4], usageinfo[5], 
      usageinfo[6], usageinfo[7], usageinfo[8], usageinfo[9]

   );

}




int main(int argc, char * const argv[])
{

   int verbose = 0;
   const char *suffix = 0;

   if ( argc == 1 ) { usage(); return 0; }

   int ch;

   while ((ch = getopt(argc, (char **)argv, "s:hv")) != -1) 
   {
      switch (ch)
      {
         case 'h':
            usage();
            return 0;
         case 's':
            suffix = optarg;
            break;
         case 'v':
            verbose = 1;
            break;
         case '?':
            default:
            usage();
            return 1;
      }
   }

   argc -= optind;
   argv += optind;

   int rc;

   if ((rc = ptree(argv, suffix, verbose)) != 0) 
      rc = 1;

   return rc;

}


static int ptree(char * const argv[], const char *suffix, int verbose)
{

   int i = 0;

   unsigned long long int lines = 0;
   unsigned long long int file_count = 0;

   FTS *ftsp = 0;
   FTSENT *p = 0, *chp = 0;
   int fts_options = FTS_COMFOLLOW | FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT;
   int rval;
   rval = 0;

   if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) 
   {
      warn("fts_open");
      return -1;
   }

   // Initialize ftsp with as many argv[] parts as possible.
   chp = fts_children(ftsp, 0);

   if (chp == NULL)
   {
      fprintf(stderr, "No files to traverse. See -h option. Exiting ...\n");
      return 1;
   }

   int lines_per_file = 0;
   FILE *file;

   char *pathptr = 0;

   int equal = 0;

   int ch;
   int prev;
   size_t suffix_len = 0;

   if (suffix)
      suffix_len = strlen(suffix);


   while ((p = fts_read(ftsp)) != NULL) 
   {

      switch (p->fts_info) 
      { 

         case FTS_F:

                    file_count++;
                    //printf("path: %s\n", p->fts_path);
                    //printf("suffix: %s\n", suffix);

                    if (suffix)
                    {
                       equal = 0;
                       pathptr = p->fts_path;
                       while (*pathptr) pathptr++;   // pathptr now points to the terminating '\0'

                       for (i = suffix_len - 1; i >= 0; i--) 
                       {
                          pathptr--;
                          if ( (!pathptr) || (*pathptr != suffix[i]) )
                          {
                             equal = 1;
                             break;
                          }
                       }
                    }  // if suffix


                    if (equal == 0)
                    {

                       file = fopen(p->fts_path, "r");    // open file for reading

                       if (file)
                       {

                          prev = '\n';     

                          while ( (ch = fgetc(file)) != EOF )   // read all characters in the file
                          {
                             if ( ch == '\n' )
                             {
                                ++lines;                        // count every newline '\n' character
                                ++lines_per_file;
                             }
                             prev = ch;                         // Keep a copy to later test whether...
                          }

                          fclose(file);

                          if ( prev != '\n' )     // ... the last line did not end in a newline.
                          {
                             ++lines;             // add the last line without a closing newline '\n' character to the line count
                             ++lines_per_file;
                          }

                          if (verbose == 1)
                             printf("%-12d%s\n", lines_per_file, p->fts_path);

                          lines_per_file = 0;

                       } else {

                          fprintf(stderr, "\ncouldn't read file: %s\n",  p->fts_path);
                          break;
                       }

                    }  // if equal

                    break;

         default:
                    break;

      }   // switch

   }   // while


   fts_close(ftsp);

   if (verbose == 1)
   {
      printf("\ntotal number of files = %llu\n", file_count);
      printf("\ntotal number of lines = %llu\n\n", lines);
   } else {
      printf("%llu\n", lines);
   }


   return 0;

}  // ptree


Clear the entire current line in Bash

"\ed": kill-whole-line
#bind '"\M-d"':kill-whole-line

# Clear the entire current line by pressing the [esc-d] key sequence;
# in contrast to ctrl-u & ctrl-k the cursor position does not matter.
# cf. http://www.bigsmoke.us/readline/shortcuts

echo [esc-d] string   


#-------------------------


/bin/cat >> ~/.inputrc <<-'EOF'

"\ed": kill-whole-line
#"\M-d": kill-whole-line

EOF

# reinitialize ~/.inputrc
exec /bin/bash    
source ~/.bash_login ~/.bashrc

# if ~/.bashrc is getting sourced from ~/.bash_login
# exec /bin/bash --login

echo [esc-d] string

Deleting a line from a file matching criteria

I was messing around trying to figure out an easier way to remove entries from my /etc/portage/package.keywords file without having to drop into VI all the time and came up with this. You can put this into a bash script to make things alot easier on yourself if you are constantly altering your mask/use/keywords files in Gentoo.

sed -i '/x11-wm\/compiz/d' /etc/portage/package.keywords


The above example will remove any line that matches the regular expression x11-wm/compiz and edit the file in place "-i".