Functions in shell scripts

I'm writing a script which is becoming a little on the lengthy side for easy management (>100 lines).  Instead of having half-a dozen nested IFs, I've chosen to use a sequence of single-level IFs and a few control variables that are set during the IFs.

However, I don't want to have to trawl through all these IFs to be able to edit the main body of the program.  I can use a function, but this still has to be defined before it's used.

Is there any way I can push this stuff down to the bottom of the script somewhere and leave me with all the nice stuff at the top to edit?

Thanks,
Steve :)
LVL 9
sda100Asked:
Who is Participating?
 
Duncan RoeConnect With a Mentor Software DeveloperCommented:
Ok, here is my sfl script as posted in answer to previous qns, but factored into functions. Hope you find it helpful:

#!/bin/sh
#set -x

# Runs the show
main()
{
  try_gnu_args
  set_personality || exit 1

# Had to inline the next bit, coz it uses shift & args are local to functions
if [ -z "$1" ];then
  echo "Usage: $j <string> [<grep option>,...]" >&2
  exit 1
else
  k="$1"
  shift
fi

do_the_grep "$@"
}

# Sets fiddly gnu arg iff we have gnu grep
try_gnu_args()
{
  grep --version >/dev/null 2>&1
  [ $? -eq 0 ] && n=-noleaf || n=
}

# Check for good invocation.
# sfl is designed to be symlinked to - which synlink is used determines behaviour.
# list of symlinks:
# lrwxrwxrwx  1 dunc users    3 2004-09-30 22:12 afl -> sfl
# lrwxrwxrwx  1 dunc users    3 2004-09-30 22:12 aflc -> sfl
# lrwxrwxrwx  1 dunc users    3 2004-09-30 22:12 afll -> sfl
# lrwxrwxrwx  1 dunc users    3 2004-09-30 22:12 afllc -> sfl
# -rwxr-xr-x  1 dunc users 1183 2006-05-04 07:59 sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 sflc -> sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 sfll -> sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 sfllc -> sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 ufl -> sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 uflc -> sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 ufll -> sfl
# lrwxrwxrwx  1 root root     3 2004-09-30 22:12 ufllc -> sfl
set_personality()
{
  j=`basename $0`
  case $j in
  u*)
    f='.. -maxdepth 2 -mindepth 2'
    w=w
    ;;
  s*)
    f=.
    w=w
    ;;
  a*)
    f=.
    w=""
    ;;
  *)
    echo bad symlink of sfl to $j
    return 1
    ;;
  esac
  case $j in
  ?fl)
    i=''
    ;;
  ?fll)
    i=''
    f="$f -follow"
    ;;
  ?flc)
    i=i
    ;;
  ?fllc)
    i=i
    f="$f -follow"
    ;;
  *)
    echo bad symlink of sfl to $j
    return 1
    ;;
  esac
  return 0
}

# Actually do the gep
do_the_grep()
{
  find $f $n -depth -type f \( \
    -name "*.c" \
    -o -name "*.cpp" \
    -o -name "*.cxx" \
    -o -name "*.cc" \
    -o -name "*.f" \
    -o -name "*.for" \
    -o -name "*.S" \
    -o -name "*.h" \
    -o -name "*.java" \
    -o -name "*.exp" \
    -o -name "*.tcl" \
    -o -name "*.expect" \
    -o -name "*.pl" \
    -o -iname "makefile" \
    -o -name "make-file" \
    -o -name "*.i" \
    -o -name "*.l" \
    -o -name "*.lex" \
    -o -name "*.y" \
    -o -name "*.yacc" \
    -o -name "*.sh" \
    \) -print|xargs -n 32 -r -e grep -${i}s${w}n "$@" -- "$k" /dev/null
}
main "$@"
0
 
PsiCopCommented:
Put the function in a different file, e.g. function.sh

Then in your script, include that file:

. function.sh

or

source function.sh
0
 
MysidiaCommented:
You can define the function later than it appears in the file by using a 2-iteration loop.

The important thing to keep in mind, is that in shell script language, defining a function
is a runtime action;  the order in the file doesn't matter, just as long as the function definition
is run before the call is run, in the script.

I.E.


for PASS in  1 2 ;
do
  if [ $PASS -eq 2 ]  ; then        
         myfunction
  fi

  if [ $PASS -eq 1 ]  ; then        
      myfnuction() {
         statement1
         statement2
      }
  fi
done
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
ahoffmannCommented:

. $0
if [ "$got_functions" -eq 1 ]; then
  # main code
fi
exit

got_functions=1
function f {
 # ..
}


you also could avoid the if condition by using $SHELL or alike, but that depends on the used shell and the shell's flavoiur on your platform, inshort: no general solution possible
0
 
Duncan RoeSoftware DeveloperCommented:
Define all your functions at the start of the script. Have a main() function first, which calls all the others in turn. The last line of your script (the only line that isn't part of a function definition) should be:
  main "$@"
You think >100 lines is long? With scripts arranged as above, you'll soon think scripts < 1000 lines are short :)
0
 
sda100Author Commented:
Thanks duncan_roe

I think I'm with you... can you give me a short example please?

Steve :)
0
 
Duncan RoeSoftware DeveloperCommented:
Hi sda100 - I don't use that pardadigm myself usually but I'm working on converting one of my scripts for you as an example.
Is taking too long just now (8AM) but will complete and post tonight
0
 
sda100Author Commented:
Thank you very much.  Long example, but I like it... and now I know what you mean by the main "$@" at the end.

Steve :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.