4

For I school project, I have to implement a shell/terminal app. But I am wondering how are command line options parsed, because it appears abit weird to be. For example for the command paste (and I believe other utilities behave similarly)

[jiewmeng@JM tmp]$ paste --help
Usage: paste [OPTION]... [FILE]...

Behavior when combining multiple options into one

[jiewmeng@JM tmp]$ paste -ds file1
file1 xxx
file1
d aaws dafd a

Here it appears options are just ignored ...

[jiewmeng@JM tmp]$ paste -sd file1

It behaves the same as paste -, waiting for stdin. But when its valid combination

[jiewmeng@JM tmp]$ paste -sd. file1
file1 xxx.file1.d aaws dafd a

It works. Shouldn't the invalid one give an error instead of waiting for stdin?

[jiewmeng@JM tmp]$ paste -d
paste: option requires an argument -- 'd'
Try 'paste --help' for more information.

Ok, makes sense d requires an argument, but ...

[jiewmeng@JM tmp]$ paste -d file1

... waits for stdin. why?

2 Answers 2

8

I find it generally confusing to look at the existing body of tools to try and gain an understanding of how command line arguments work.

Why you might ask?

Well there are many situations where the author of a given command line tool presents command line arguments to the user in what makes the most sense for their tool. So consequently the options can be fairly complex and confusing until you get your head around them.

Don't get me wrong, it's good to get an appreciation for the different ways options can be presented, but when starting out, it's probably better to start with an actual tool that one would use to parse command line arguments, such as getopts.

getopts

So I would suggest taking a look at getopts, it's included in Bash if you want to get an appreciation for how one would parse their own command line arguments if they were building a shell script that required parsing arguments.

Example

#!/bin/sh

# Initialize our own variables:
output_file=""
verbose=0

OPTIND=1 # Reset is necessary if getopts was used previously in the script.
         # It is a good idea to make this local in a function.

while getopts "hvf:" opt; do
    case "$opt" in
        h)
            show_help
            exit 0
            ;;
        v)  verbose=1
            ;;
        f)  output_file=$OPTARG
            ;;
        '?')
            show_help >&2
            exit 1
            ;;
    esac
done
shift $((OPTIND-1)) # Shift off the options and optional --.

echo "verbose=$verbose, output_file='$output_file', Leftovers: $@"

# End of file
3

paste -d takes a mandatory argument.

See the man page

     -d, --delimiters=LIST
          reuse characters from LIST instead of TABs

This format really means

     -d LIST or --delimiters=LIST
          reuse characters from LIST instead of TABs

So with paste -d file1, you're setting LIST to file1, and no file name is specified. And as the man page says:

    With no FILE, or when FILE is -, read standard input.

With paste -ds file1, you're setting delimiter to s. You'd have to supply multiple files to see the effect.

Compare

$ paste <(printf 'foo\nbar\n') <(printf 'one\ntwo\n') 
foo<TAB>one
bar<TAB>two
$ paste -ds <(printf 'foo\nbar\n') <(printf 'one\ntwo\n')
foosone
barstwo

You must log in to answer this question.

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