93

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
140

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
  • 1
    @kylex, no, since there is no long option named just "c" and the -- means a long option, not a single character option follows.
    – psusi
    May 10 '12 at 14:37
  • 17
    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
    May 10 '12 at 14:42
  • 8
    @mulaz, yes, cdrecord does quite a few goofy things.
    – psusi
    May 10 '12 at 14:46
  • 12
    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
    May 10 '12 at 19:51
  • 4
    @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
    Apr 2 '18 at 15:25
23

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

1
  • 3
    So why is it java -version and ant -version, then ?
    – killjoy
    Mar 30 '18 at 14:48
10

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.

6

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). Jul 30 at 11:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.