118

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?

2

5 Answers 5

165

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.

12
  • 24
    Sometimes 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
    – mulaz
    Commented May 10, 2012 at 14:42
  • 9
    @mulaz, yes, cdrecord does quite a few goofy things.
    – psusi
    Commented May 10, 2012 at 14:46
  • 13
    also bear in mind -- used on its own usually signifys the end of options. see here for more info: unix.stackexchange.com/questions/11376/…
    – Sirex
    Commented May 10, 2012 at 19:51
  • 2
    So why is it java -version and ant -version, then ?
    – killjoy
    Commented Mar 30, 2018 at 14:47
  • 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.
    – psusi
    Commented Apr 2, 2018 at 15:25
28

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.

source

2
  • 4
    So why is it java -version and ant -version, then ?
    – killjoy
    Commented Mar 30, 2018 at 14:48
  • @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.
    – Mecki
    Commented Jan 4, 2022 at 0:42
13

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.

7

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.

0

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.
}
1
  • 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). Commented Jul 30, 2021 at 11:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .