[bash] code review request
Hello all,
I have just written my first big function in bash and I'm not happy with it b/c of the use of getopt. I chose GNU getopt overs bash getopts builtin because it can understand and parse --long-options, however, it dosn't know how to parse arguments that include spaces, even when you quote them. The second thing I'm not happy with is the function definition of _usage inside the main function. I learned that function definitions are global, so it's no use to define a function inside a function with the intention of hiding it to others. I don't know how to do that in bash, or if I should even bother with it. Here's the code, if anyone wants to discuss it. Code:
function notes.search { |
Unless you want to support POSIX short option combining then I find it just as easy to parse options manually rather than use getopt or getopts.
getopt is typically used with an 'eval' on the set -- "$VAR" line, which solves some of the whitespace issues. Use of the 'eval' is one of the reasons I don't like to use getopt, along with the fact it's not standard and there are incompatible versions out there. In bash scripts I prefer to stick with getopts and POSIX short-options where possible, or just handle options manually: if that is not possible,or where I don't care about option combining. For your usage function scoping issue... the best you can likely do is use a good naming convention to keep things tidy: notes.search() and notes.search.usage() perhaps? |
Thanks for the nice feedback GazL!
I like your naming suggestion very much! Thanks also for explaining about the eval. I saw that in some bash scripts and didn't understand why it was used, or why would anyone use eval at all. I learned in my early days of computing that eval was another name for evil. I will consider rewriting the options parsing without getopt or getopts. It's interesting that bash doesn't seem to have a universal solution for that. Maybe writing it by hand isn't that hard after all. Appended to my todo-list. |
Put the code into ShellCheck and it highlights several issues to be resolved. (Also, there is a command-line version of ShellCheck which can be used offline.)
Actually, I'm surprising that ShellCheck didn't warn about not to use getopt. As per that link: "Every Unix system which still ships getopt includes warnings in its man page telling you not to use it." Here is how to correctly parse command line options with Bash. |
Quote:
I should consider rewriting the options parsing loop by hand. Thanks for the link! |
Quote:
I typically do it like this: Code:
#!/bin/sh One can add additional checks for this sort of stuff, but, personally I favour the use of -l<filename> or --logfile=<filename> formats to avoid the situation. |
Quote:
I do tend to put "--" as the first case too, but Wooledge's version still works. |
The problem will come should you start using wildcards in any of the case matches that preceed '--' For example, you could run into trouble if you had a nested case, like this
Code:
-?) # process short option: Code:
--) shift ; break ;; |
Given the example already includes short options, I'm unconvinced that's a likely scenario.
It is an easy change though, so I guess you could hop on IRC and see if GreyCat agrees. No reason to split short/long options though, that's just unnecessary duplication. |
So if you are going to go the Wooledge Wiki, there is plenty to read :)
So here are my personal thoughts (so please take what you like and abaandon the rest :) ) 1. I prefer to use cat and a heredoc when creating a usage message: Code:
_usage() Code:
declare -a usage 3. I agree with the others about just write your own parameter parsing 4. I don't see the need to assign to a variable and then call set to get you back where you started, or use a while loop: Code:
for param in $(getopt -uo EFr -l all,log,txt,LOG,TXT,newer-than:,headings,recent,all -- $@) 6. Check out Wooledge page on why not to process ls output 7. Also on Wooledge is issues (probably not affecting you here) around "command | while" and subshells and variable issues 8. Lastly, you invite discussion which some may look at requiring a test run with known factors, however there are several variables and commands which only exist on your system. So please remember to try and include a working set of options :) Also, welcome on your bash journey :) |
Interesting idea. You can avoid the ugly IFS stuff if you do it something like this:
Code:
func1() |
Quote:
|
Quote:
Use a command group Code:
[[ -z $pattern ]] && { Code:
if [[ -z $pattern ]]; then Less overhead: a multi-line echo Code:
_usage() |
Here's my take on args, using keyword=value
keywords become variables, quoted whitespace works and "$@" is used normally Code:
# designed with korn, works with bash and most shells |
All times are GMT -5. The time now is 04:03 AM. |