I know boost::program_options from c++ which enables me to write user- friendly command-line options in almost no time. With "user- friendly" I mean, short and long options and a descriptive help command which would look similar to this:
Copy standard input to each FILE, and also to standard output.
-a, --append append to the given FILEs, do not overwrite
-i, --ignore-interrupts ignore interrupt signals
--help display this help and exit
--version output version information and exit
For myself I had to find out that this is really awkward in bash with the built-in getopts only supporting short options. Is this correct or am I wrong?
How would you implement user friendly command line options? If you know any links, best practices or in depths tutorials I would be really much appreciated.
GNU getopt supports long options and can be used from any Bourne-like or csh-like shell. ksh93's builtin getopts supports long options as well. zsh has a zparseopts.
There's a POSIX shell implementation of getopts (as a shell function) that supports long options at http://stchaz.free.fr/getopts_long.sh
Thank you for pointing me to the correct sources of information.
I decided to do it this way https://github.com/Mythli/tech/blob/master/bash/getopt.sh
The code is pretty straightforward so no explanation should be needed.
Related
Is there an option to describe a command and list its possible options in bash/zsh? I tried looking for one and I could only find -h but it does not work for me and gives me the error bad option: -h on zsh and -h: invalid option in bash. Same for -?.
There is a separate command man. Most commands, certainly all the traditional commands, have a man page. Try man man.
The GNU coding standards state, that:
The standard --help option should output brief documentation for how to invoke the program, on standard output, then exit successfully. Other options and arguments should be ignored once this is seen, and the program should not perform its normal function.
So, for GNU programs, --help should provide you with the requested output (should, not will).
And for the rest: it is just wild west. Some implement -h for help. And others just believe that Google is the source for documentation.
I'm trying to create an overly simplified version of bash, I've tried split the program into "lexer + expander, parser, executor".
In the lexer i store my data (commands, flags, files) and create tokens out of them , my procedure is simply to loop through given input char by char and use a state machine to handle states, states are either a special character, an alphanumeric character or space.
Now when i'm at an alphanumeric state i'm at a command, the way i know where the next flag is when i encounter again alphanumeric state or if input[i] == '-', now the problem is with multi-flag commands.
For example:
$ ls -la | grep "*.c"
I successfully get the command ls, grep and the flag -la, *.c.
However with multi-flag commands like.
$ sed -i "*.bak" "s/a/b/g" file1 file2
It seems to me very difficult, and i can't figure out yet, how can i know where the flags to a specific command ends, so my question is how bash parse these multi-flags commands ? any suggestions regarding my problem, would be appreciated !
The shell does not attempt to parse command arguments; that's the responsibility of the utility. The range of possible command argument syntaxes, both in use and potentially useful, is far too great to attempt that.
On Unix-like systems, the shell identifies individual arguments from the command line, mostly by splitting at whitespace but also taking into account the use of quotes and a variety of other transformations, such as "glob expansion". It then makes a vector of these arguments ("argv") and passes the vector to execve, which hands them to the newly created process.
On Windows systems, the shell doesn't even do that. It just hands over the command-line as a string, and leaves it to the command-line tool to do everything. (In order to provide a modicum of compatibility, there's an intermediate layer which is called by the application initialization code, which eventually calls main(). This does some basic argument-splitting, although its quoting algorithm is quite a bit simplified from that used by a Unix shell.)
No command-line shell that I know of attempts to identify command-line flags. And neither should you.
For a bit of extracurricular reading, here's the description of shell parsing from the Posix standard: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html. Trying to implement all that goes far beyond the requirements given to you for this assignment, and I'm certainly not recommending that you do that. But it might still be interesting, and understanding it will help you immensely if you start using a shell.
Alternatively, you could try reading the Bash manual, which might be easier to understand. Note that Bash implements a lot of extensions to the Posix standard.
I have aliases for many commands with their verbose flags, e.g.:
alias ninja='ninja --verbose -j 0'
Is there a mechanism in bash, where I can deactivate this flag afterwards?
I tried stuff like:
ninja --verbose=0
but that didn't work out.
I know that I can hide my output with /dev/null or that I can execute the binary directly with /path/to/ninja, but that's not the intent of my question. The answer might be command specific and depends on which mechanism for passing parameters the appropriate program uses, e.g. getopts. Anyways, I am looking forward to your help.
EDIT:
From comments I learned, that command ninja or escaping like nin\ja will ignore the complete alias, but not a specific parameter.
I'm working on bash auto-completion for a project I'm the maintainer of. You can find the script here. I've cobbled this together with some hacking on my own, and with the help of some contributors who understand that completion APIs better than I do.
What we have works great -- with one exception. We can manage a completion like like this
//type
pestle.phar som[TAB]
//completes to
pestle.phar some-command-name
However, once we're here we lose file path/name completion that's a part of the stock bash shell. That is, working off the previous example, if a user types
//type
pestle.phar some-command-name /va[TAB]
we'd like it to complete to
//completes to the following, because var exists
pestle.phar some-command-name /var
Is there a way to just tell the complete command something like
Hey, in addition to everything we're telling you to do with our custom bash function, also keep your normal file path completion
If not, is there there some known science/boilerplate to reimplementing the file path completion in your own custom base completion functions?
Some other answers and the docs seem to indicate that the -o filenames or -o bashdefault options should take care of this -- but it doesn't seem to be working on OS X 10.11. I'm not sure if I misunderstand -o, or if the code in my completion files somehow overrides the -o behavior, or if OS X is doing it's I'm only a mostly well behaved unix thing.
Also -- if it's not obvious -- this is my first deep bash completion rodeo. If I've said something seemingly dumb/naive above please let me know. I may be looking for a fish right now, but I'd like to learn to fish in the bash completion river myself.
I think -o default (without -o filenames) should work for you. According to the manual:
bashdefault
Perform the rest of the default bash completions if the compspec generates no matches.
default
Use readline's default filename completion if the compspec generates no matches.
filenames
Tell readline that the compspec generates filenames, so it can perform any filename-specific processing (like adding a slash to directory
names, quoting special characters, or suppressing trailing spaces). Intended to be used with shell functions.
(Also see 'complete -d -o default cd' issue for the difference between -o default and -o bashdefault.)
I'm making some command-line tools for some research I'm doing. I'd like these tools to follow commonly used conventions regarding command line programs in Unix.
Should I use flags or just list parameters?
program one two three
program -a one -b two -c three
Where in the list of commands does the input file normally go, or is it better to < it into the program?
What about the output filename?
Should I specify the file extension for the output format, or have my program automatically put the correct extension on?
When the user enters an invalid command, is there a prototypical "correct usage" message?
Is "--help" or "-h" required?
Also, is there some sort of header file I can include that would help with managing these?
If you're looking for a "standard", then you could do worse than look at GNU's Standards for Command Line Interfaces. Other standards are available.
As far as coding for this goes, take a look at boost::program_options. Not only will this save you rolling a lot of your own code, but it does a good job of formatting the options for presenting to the user (the prototypical "correct usage" message, you asked for).
In answer to your specific questions:
Where in the list of commands does the input file normally go, or is it better to < it into the program?
I would expect these to come at the end of a command line. Like in GNU grep. If you are only processing one file and would like to make stdin available as an input source, that would not surprise most users.
If your command processes lots of files, then it would be unusual to have to specify a switch before the filenames. Think cat.
What about the output filename?
A -o or --output option is fairly common. If your file takes exactly one input and one output, then program inputfile outputfile would not surprise many users. If no output file is specified, perhaps you'll output to stdout; that would not be unusual behaviour and would allow your users to pipe the output through other commands (such as grep, less, etc...), They could also redirect stdout to a file using >.
Should I specify the file extension for the output format, or have my program automatically put the correct extension on?
This is probably a matter for debate. If I specified an output filename, I would expect to find that file created (or replaced, after a prompt) without the program changing the name.
When the user enters an invalid command, is there a prototypical "correct usage" message?
Using GNU grep as an example again:
grep: unrecognized option '--incorrect'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
This wouldn't surprise too many users and points them in the right direction if they've made a typo without swamping them with information.
Is "--help" or "-h" required?
That depends on your customer! I find it frustrating when this option isn't available.
Usually speaking, flags are there for providing options and parameter are for passing information. If you have input,output file as command line argument, use flags like -i -o, so sequence will not matter. -h is required if you want to (and need to) give documentation.