I'm new to working in the shell and the usage of these commands seems arbitrary. Is there a reason one flag has a single dash and another might have a double dash?
5 Answers
A single hyphen can be followed by multiple single-character flags. A double hyphen prefixes a single, multicharacter option.
Consider this example:
tar -czf
In this example, -czf
specifies three single-character flags: c
, z
, and f
.
Now consider another example:
tar --exclude
In this case, --exclude
specifies a single, multicharacter option named exclude
. The double hyphen disambiguates the command-line argument, ensuring that tar
interprets it as exclude
rather than a combination of e
, x
, c
, l
, u
, d
, and e
.
-
24Sometimes even long commands can be single-dashed. For example 'cdrecord' uses all single-dashed commands (-eject -dao ...). It all depends on the program, but most(!) of them use - for single and -- for multiple-character (long) commands– mulazMay 10, 2012 at 14:42
-
9
-
13also bear in mind -- used on its own usually signifys the end of options. see here for more info: unix.stackexchange.com/questions/11376/…– SirexMay 10, 2012 at 19:51
-
2
-
8@killjoy, because whether through ignorance or choice, the authors of those programs did not follow the convention of course. Just like
cdrecord
mentioned years ago in the above comments.– psusiApr 2, 2018 at 15:25
It all depends on the program. Usually "-" is used for 'short' options (one-letter, -h), and "--" is used for "long"(er) options (--help).
Short options can usually be combined (so "-h -a" is same as "-ha")
In Unix-like systems, the ASCII hyphen–minus is commonly used to specify options. The character is usually followed by one or more letters. An argument that is a single hyphen–minus by itself without any letters usually specifies that a program should handle data coming from the standard input or send data to the standard output. Two hyphen–minus characters ( -- ) are used on some programs to specify "long options" where more descriptive option names are used. This is a common feature of GNU software.
-
4
-
@killjoy Because those are no UNIX commands and software developers are free to make their programs follow different rules than those of traditional UNIX commands.– MeckiJan 4, 2022 at 0:42
It's really a convention. However, it can aid parsers to know more efficiently about options passed to the program.
Besides, there are neat utilities that can help parsing these commands, such as getopt(3)
or the non-standard getopt_long(3)
to help parse the arguments of a program.
It is nice, for we can have multiple short options combined, as other answers say, like tar -xzf myfile.tar.gz
.
If there was a "lisa" argument for ls
, there would probably have a different meaning to type ls -lisa
than ls --lisa
. The former are the l
, i
, s
, and a
parameters, not the word.
In fact, you could write ls -l -i -s -a
, meaning exactly the same as ls -lisa
, but that would depend on the program.
There are also programs that don't obey this convention. Most notably for my sight, dd
and gcc
.
short options with single dash vs long options with double dash
short options can be combined into a single argument;
for example: ls -lrt #instead of ls -l -r -t
If we allow long options with single dash, it causes ambiguity. To resolve this we use double dash for long options.
Another case is when a script calls another program, it may be necessary to separate the options for the first script from those passed to the second program. For example, you can write a bash function to parse the command line, similar to the function below. Then use a command line similar to the following. In this case the double dashes keep the options for each program separated and allows the built-in parser's error handling to work as intended. Of course, there may special cases that would need to be handled.
firstscript --firstScriptOption -- --optForSecondProgram
# Parse the command line and set variables to control logic.
parseCommandLine() {
local additionalOpts exitCode optstring optstringLong
# Indicate specification for single character options:
# - 1 colon after an option indicates that an argument is required
# - 2 colons after an option indicates that an argument is optional, must use -o=argument syntax
optstring="h"
# Indicate specification for long options:
# - 1 colon after an option indicates that an argument is required
# - 2 colons after an option indicates that an argument is optional, must use --option=argument syntax
optstringLong="help"
# Parse the options using getopt command:
# - the -- is a separator between getopt options and parameters to be parsed
# - output is simple space-delimited command line
# - error message will be printed if unrecognized option or missing parameter but status will be 0
# - if an optional argument is not specified, output will include empty string ''
GETOPT_OUT=$(getopt --options ${optstring} --longoptions ${optstringLong} -- "$@")
exitCode=$?
if [ ${exitCode} -ne 0 ]; then
# Call a separate function to print usage.
printUsage
exit 1
fi
# The following constructs the command by concatenating arguments:
# - the $1, $2, etc. variables are set as if typed on the command line
# - special cases like --option=value and missing optional arguments are generically handled
# as separate parameters so shift can be done below
eval set -- "${GETOPT_OUT}"
# Loop over the options:
# - the error handling will catch cases were argument is missing
# - shift over the known number of options/arguments
while true; do
#echo "Command line option is ${opt}"
case "$1" in
-h|--help) # Print usage of this script
printUsage
shift
;;
--) # No more arguments - following arguments are passed to the second program.
shift
break
;;
*) # Unknown option - will never get here because getopt catches up front
# and remaining options are after --
echo "Invalid option $1." >&2
printUsage
exit 1
;;
esac
done
# Get a list of all command line options that do not correspond to dash options:
# - These are "non-option" arguments after --
# - For example, one or more file or folder names that need to be processed.
# - If multiple values, they will be delimited by spaces.
# - Command line * will result in expansion to matching files and folders.
shift $((OPTIND-1))
additionalOpts=$*
echo "Additional options: ${additionalOpts}"
# The additional options would be passed to the second program.
}
-
this is different, the double hyphen in your example signifies the end of the command options, therefore, anything after it will be interpreted as text (not a command argument). In the example above, the
--optForSecondProgram
will be interpreted as text or filename (depending on the program). Jul 30, 2021 at 11:08