Prev: alternative for ctime
Next: multiple cmnds in ssh..
From: Scott Bass on 27 Apr 2010 03:07 Hi, I'm writing a script (ksh88) which is very modular, with a number of function definitions, then a main section which "glues it all together". One of these functions is to parse the command line for arguments. Here is an excerpt: #=================================================================== function parse_command_line # process command line arguments #=================================================================== { while getopts :o:a:h optchar do case $optchar in "o") # specify options for the sas program options=$OPTARG ;; "a") # specify delayed start of job starttime=$OPTARG ;; "h") # display help screen show_help "$0 command - help screen:" exit 0 ;; "?") # illegal option specified show_help "$OPTARG is not a valid option." exit 1 ;; ":") # Option argument is missing. show_help "$OPTARG requires an argument." exit 1 ;; esac done # Shift past option arguments shift $(($OPTIND - 1)) # Remaining arguments are program files jobs=$* } Then later, at the bottom of the script: #################################################################### # MAIN PROGRAM #################################################################### # If running attached to a terminal, the script is running in a shell if [[ $usertty != "not a tty" ]] then initialize_variables || exit $? parse_command_line $* || exit $? <<<<<<<<<<<<<<<<<<<<<< check_start_time || ( show_help "Invalid date specified: $starttime"; exit $? ) build_submit_parameters $jobs || exit $? submit_sas_program || exit $? else # Running detached from a terminal, so this script is called by bsub runsas $jobs || exit $? fi The script can be called with the switches -a, -o, and -h. Arguments following the switches are programs to execute. The problem is, some of the options to be passed to the internal program (sas) also look like command switches. For example, if my main script is named "foo", here is an example invocation: foo -o "-noautoexec -nosource -notes" -a "00:00" my_program_file.sas If I don't quote the command line arguments (as above), the getopts processing fails. If I quote the command line arguments (eg. parse_command_line "$*"), then the list of jobs are not set properly. Questions: 1) Is there any way I can keep this modular, or do I need to move the code in parse_command_line into open code (the "main" program)? 2) Is there a way I can shift the arguments in the parse_command_line function and have it affect the global list of arguments? IOW so I can substitute $* for $jobs in the above code. I've read that ksh functions cannot pass arguments by reference, so I assume I can't do this. Unless I can use typeset to make the $* array of arguments global, not just the array of arguments passed to the function? 3) Is best practice to use "return <rc>" rather than "exit <rc>" in functions? 4) Minor: are $* and $@ identical? Thanks, Scott
From: Scott Bass on 27 Apr 2010 03:15 On Apr 27, 5:07 pm, Scott Bass <sas_l_...(a)yahoo.com.au> wrote: > Hi, > > I'm writing a script (ksh88) which is very modular, with a number of > function definitions, then a main section which "glues it all > together". One of these functions is to parse the command line for > arguments. > > Here is an excerpt: > > #=================================================================== > function parse_command_line # process command line arguments > #=================================================================== > { > while getopts :o:a:h optchar > do case $optchar in > "o") # specify options for the sas program > options=$OPTARG > ;; > "a") # specify delayed start of job > starttime=$OPTARG > ;; > "h") # display help screen > show_help "$0 command - help screen:" > exit 0 > ;; > "?") # illegal option specified > show_help "$OPTARG is not a valid option." > exit 1 > ;; > ":") # Option argument is missing. > show_help "$OPTARG requires an argument." > exit 1 > ;; > esac > done > > # Shift past option arguments > shift $(($OPTIND - 1)) > > # Remaining arguments are program files > jobs=$* > > } > <...> > Questions: > 1) Is there any way I can keep this modular, or do I need to move the > code in parse_command_line into open code (the "main" program)? <...> Sorry I should also add that the script that I'm enhancing/updating has all the code in "open code" (i.e. no functions) and processes the example scenario fine. I think the issue is the quoted argument (-o "- noautoexec etc") "loses" its quoting when passed to the parse_command_line function.
From: Janis Papanagnou on 27 Apr 2010 03:46 Scott Bass schrieb: > Hi, > > I'm writing a script (ksh88) which is very modular, with a number of > function definitions, then a main section which "glues it all > together". One of these functions is to parse the command line for > arguments. > > Here is an excerpt: > > #=================================================================== > function parse_command_line # process command line arguments > #=================================================================== > { > while getopts :o:a:h optchar > do case $optchar in > "o") # specify options for the sas program > options=$OPTARG > ;; > "a") # specify delayed start of job > starttime=$OPTARG > ;; > "h") # display help screen > show_help "$0 command - help screen:" > exit 0 > ;; > "?") # illegal option specified > show_help "$OPTARG is not a valid option." > exit 1 > ;; > ":") # Option argument is missing. > show_help "$OPTARG requires an argument." > exit 1 > ;; > esac > done > > # Shift past option arguments > shift $(($OPTIND - 1)) > > # Remaining arguments are program files > jobs=$* > } > > Then later, at the bottom of the script: > > #################################################################### > # MAIN PROGRAM > #################################################################### > > # If running attached to a terminal, the script is running in a shell > if [[ $usertty != "not a tty" ]] > then > initialize_variables || exit $? > parse_command_line $* || exit $? You most likely want parse_command_line "$@" || exit $? > <<<<<<<<<<<<<<<<<<<<<< > check_start_time || ( show_help "Invalid date > specified: $starttime"; exit $? ) > build_submit_parameters $jobs || exit $? > submit_sas_program || exit $? > else > # Running detached from a terminal, so this script is called by bsub > runsas $jobs || exit $? > fi > > The script can be called with the switches -a, -o, and -h. Arguments > following the switches are programs to execute. > > The problem is, some of the options to be passed to the internal > program (sas) also look like command switches. For example, if my > main script is named "foo", here is an example invocation: > > foo -o "-noautoexec -nosource -notes" -a "00:00" my_program_file.sas > > If I don't quote the command line arguments (as above), the getopts > processing fails. > > If I quote the command line arguments (eg. parse_command_line "$*"), > then the list of jobs are not set properly. > > Questions: > 1) Is there any way I can keep this modular, or do I need to move the > code in parse_command_line into open code (the "main" program)? > > 2) Is there a way I can shift the arguments in the parse_command_line > function and have it affect the global list of arguments? It's not really necessary to do so. > IOW so I > can substitute $* for $jobs in the above code. (Saying that without looking into the details of your program...) Switch to "$@" and you should be fine. > I've read that ksh > functions cannot pass arguments by reference, so I assume I can't do > this. Ksh93 supports call by name reference by typeset -n. > Unless I can use typeset to make the $* array of arguments > global, not just the array of arguments passed to the function? > > 3) Is best practice to use "return <rc>" rather than "exit <rc>" in > functions? Depending on the platform. There was an old, I think, AIX 3.5 ksh88 that had a bug with return/exit from functions. Return will return from a function (or program if it's in the main code), exit should exit the program. > > 4) Minor: are $* and $@ identical? They are not the same if they are double quoted. In quite all cases you certainly want "$@", which is different from "$*". "$@" keeps the argument structure intact. "$*" makes one huge argument. Janis > > Thanks, > Scott
From: Scott Bass on 29 Apr 2010 10:24 On Apr 27, 5:46 pm, Janis Papanagnou <janis_papanag...(a)hotmail.com> wrote: > Scott Bass schrieb: > > > Hi, > > > I'm writing a script (ksh88) which is very modular, with a number of > > function definitions, then a main section which "glues it all > > together". One of these functions is to parse the command line for > > arguments. > > > Here is an excerpt: > > > #=================================================================== > > function parse_command_line # process command line arguments > > #=================================================================== > > { > > while getopts :o:a:h optchar > > do case $optchar in > > "o") # specify options for the sas program > > options=$OPTARG > > ;; > > "a") # specify delayed start of job > > starttime=$OPTARG > > ;; > > "h") # display help screen > > show_help "$0 command - help screen:" > > exit 0 > > ;; > > "?") # illegal option specified > > show_help "$OPTARG is not a valid option." > > exit 1 > > ;; > > ":") # Option argument is missing. > > show_help "$OPTARG requires an argument." > > exit 1 > > ;; > > esac > > done > > > # Shift past option arguments > > shift $(($OPTIND - 1)) > > > # Remaining arguments are program files > > jobs=$* > > } > > > Then later, at the bottom of the script: > > > #################################################################### > > # MAIN PROGRAM > > #################################################################### > > > # If running attached to a terminal, the script is running in a shell > > if [[ $usertty != "not a tty" ]] > > then > > initialize_variables || exit $? > > parse_command_line $* || exit $? > > You most likely want > > parse_command_line "$@" || exit $? > > Questions: > > 1) Is there any way I can keep this modular, or do I need to move the > > code in parse_command_line into open code (the "main" program)? > > > 2) Is there a way I can shift the arguments in the parse_command_line > > function and have it affect the global list of arguments? > > It's not really necessary to do so. > > > IOW so I > > can substitute $* for $jobs in the above code. > > (Saying that without looking into the details of your program...) > Switch to "$@" and you should be fine. <rest of thread deleted> Thanks Janis, that helped a lot. However, I still need a way to have the command line parsing code modify the global list of arguments. A short test script: #!/bin/ksh function foo { echo 1 $@ shift shift shift echo 2 $@ } echo 0 $@ foo "$@" echo 3 $@ Results: test_script a b c d e f 0 a b c d e f 1 a b c d e f 2 d e f 3 a b c d e f I need 3 to equal 2. Reason: the outer script parses the command line, processing arguments and shifting the results. I return the list of jobs in $jobs. However, I also want the inner script to be standalone, processing $@ as a list of jobs if called directly. Thanks, Scott
From: Janis Papanagnou on 29 Apr 2010 11:10
Scott Bass schrieb: > On Apr 27, 5:46 pm, Janis Papanagnou <janis_papanag...(a)hotmail.com> > wrote: >> Scott Bass schrieb: >> >>> Hi, >>> I'm writing a script (ksh88) which is very modular, with a number of >>> function definitions, then a main section which "glues it all >>> together". One of these functions is to parse the command line for >>> arguments. >>> Here is an excerpt: >>> #=================================================================== >>> function parse_command_line # process command line arguments >>> #=================================================================== >>> { >>> while getopts :o:a:h optchar >>> do case $optchar in >>> "o") # specify options for the sas program >>> options=$OPTARG >>> ;; >>> "a") # specify delayed start of job >>> starttime=$OPTARG >>> ;; >>> "h") # display help screen >>> show_help "$0 command - help screen:" >>> exit 0 >>> ;; >>> "?") # illegal option specified >>> show_help "$OPTARG is not a valid option." >>> exit 1 >>> ;; >>> ":") # Option argument is missing. >>> show_help "$OPTARG requires an argument." >>> exit 1 >>> ;; >>> esac >>> done >>> # Shift past option arguments >>> shift $(($OPTIND - 1)) >>> # Remaining arguments are program files >>> jobs=$* >>> } >>> Then later, at the bottom of the script: >>> #################################################################### >>> # MAIN PROGRAM >>> #################################################################### >>> # If running attached to a terminal, the script is running in a shell >>> if [[ $usertty != "not a tty" ]] >>> then >>> initialize_variables || exit $? >>> parse_command_line $* || exit $? >> You most likely want >> >> parse_command_line "$@" || exit $? > > >>> Questions: >>> 1) Is there any way I can keep this modular, or do I need to move the >>> code in parse_command_line into open code (the "main" program)? >>> 2) Is there a way I can shift the arguments in the parse_command_line >>> function and have it affect the global list of arguments? >> It's not really necessary to do so. >> >>> IOW so I >>> can substitute $* for $jobs in the above code. >> (Saying that without looking into the details of your program...) >> Switch to "$@" and you should be fine. > > <rest of thread deleted> > > Thanks Janis, that helped a lot. However, I still need a way to have > the command line parsing code modify the global list of arguments. A call of shift in the function will shift the arguments provided to the function, not in the global environment. > > A short test script: > > #!/bin/ksh > > function foo > { > echo 1 $@ > shift > shift > shift > echo 2 $@ > } > > echo 0 $@ > foo "$@" > echo 3 $@ > > Results: > > test_script a b c d e f > 0 a b c d e f > 1 a b c d e f > 2 d e f > 3 a b c d e f > > I need 3 to equal 2. Reason: the outer script parses the command > line, processing arguments and shifting the results. I return the > list of jobs in $jobs. However, I also want the inner script to be > standalone, processing $@ as a list of jobs if called directly. As last line in your function foo add print 3 or maybe print $# and call the function as shiftvalue=$( foo "$@" ) shift $shiftvalue or resp. remainingargs=$( foo "$@" ) shift $(( $# - $remainingargs )) (Not that this would look any better than a hack.) Janis > Thanks, > Scott |