Browse Source

--help option and help command should print to stdout not stderr

    --help and help are successful commands so output should not go to error.

    QE teams have requested this change, also users doing docker help | less
    or docker run --help | less would expect this to work.

    Usage statement should only be printed when the user asks for it.
    Errors should print error message and then suggest the docker COMMAND --help
    command to see usage information.

    The current behaviour causes the user to have to search for the error message
    and sometimes scrolls right off the screen.  For example a error on a
    "docker run" command is very difficult to diagnose.

    Finally erros should always exit with a non 0 exit code, if the user
    makes a CLI error.

Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)
Dan Walsh 10 năm trước cách đây
mục cha
commit
a2b529ead2

+ 5 - 4
api/client/cli.go

@@ -75,8 +75,8 @@ func (cli *DockerCli) Cmd(args ...string) error {
 	if len(args) > 0 {
 		method, exists := cli.getMethod(args[0])
 		if !exists {
-			fmt.Println("Error: Command not found:", args[0])
-			return cli.CmdHelp()
+			fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
+			os.Exit(1)
 		}
 		return method(args[1:]...)
 	}
@@ -90,9 +90,10 @@ func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet
 		if flags.FlagCountUndeprecated() > 0 {
 			options = "[OPTIONS] "
 		}
-		fmt.Fprintf(cli.err, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description)
+		fmt.Fprintf(cli.out, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description)
+		flags.SetOutput(cli.out)
 		flags.PrintDefaults()
-		os.Exit(2)
+		os.Exit(0)
 	}
 	return flags
 }

+ 184 - 64
api/client/commands.go

@@ -64,6 +64,8 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
 		method, exists := cli.getMethod(args[0])
 		if !exists {
 			fmt.Fprintf(cli.err, "Error: Command not found: %s\n", args[0])
+			fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
+			os.Exit(1)
 		} else {
 			method("--help")
 			return nil
@@ -83,13 +85,18 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
 	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
 	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 
 	var (
 		context  archive.Archive
@@ -254,10 +261,16 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
 	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
 	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
 	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	err := cmd.Parse(args)
 	if err != nil {
 		return nil
 	}
+	if *help {
+		cmd.Usage()
+		return nil
+	}
 	serverAddress := registry.IndexServerAddress()
 	if len(cmd.Args()) > 0 {
 		serverAddress = cmd.Arg(0)
@@ -390,13 +403,18 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
 // 'docker wait': block until a container stops
 func (cli *DockerCli) CmdWait(args ...string) error {
 	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 	var encounteredError error
 	for _, name := range cmd.Args() {
 		status, err := waitForExit(cli, name)
@@ -416,10 +434,8 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() > 0 {
-		cmd.Usage()
-		return nil
+	if cmd.BadArgs(flag.Exact, 0) {
+		os.Exit(1)
 	}
 	if dockerversion.VERSION != "" {
 		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
@@ -462,9 +478,8 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() > 0 {
-		cmd.Usage()
-		return nil
+	if cmd.BadArgs(flag.Exact, 0) {
+		os.Exit(1)
 	}
 
 	body, _, err := readBody(cli.call("GET", "/info", nil, false))
@@ -579,13 +594,18 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
 func (cli *DockerCli) CmdStop(args ...string) error {
 	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	v := url.Values{}
 	v.Set("t", strconv.Itoa(*nSeconds))
@@ -606,13 +626,18 @@ func (cli *DockerCli) CmdStop(args ...string) error {
 func (cli *DockerCli) CmdRestart(args ...string) error {
 	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	v := url.Values{}
 	v.Set("t", strconv.Itoa(*nSeconds))
@@ -664,15 +689,19 @@ func (cli *DockerCli) CmdStart(args ...string) error {
 		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
 		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
 		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
+		help      = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	hijacked := make(chan io.Closer)
 
@@ -778,10 +807,8 @@ func (cli *DockerCli) CmdUnpause(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 1 {
-		cmd.Usage()
-		return nil
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
 	}
 
 	var encounteredError error
@@ -801,10 +828,8 @@ func (cli *DockerCli) CmdPause(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 1 {
-		cmd.Usage()
-		return nil
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
 	}
 
 	var encounteredError error
@@ -822,13 +847,18 @@ func (cli *DockerCli) CmdPause(args ...string) error {
 func (cli *DockerCli) CmdInspect(args ...string) error {
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	var tmpl *template.Template
 	if *tmplStr != "" {
@@ -901,13 +931,18 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
 
 func (cli *DockerCli) CmdTop(args ...string) error {
 	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() == 0 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 	val := url.Values{}
 	if cmd.NArg() > 1 {
 		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
@@ -936,13 +971,17 @@ func (cli *DockerCli) CmdTop(args ...string) error {
 
 func (cli *DockerCli) CmdPort(args ...string) error {
 	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
 	if err != nil {
@@ -995,13 +1034,18 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
 		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
 		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
 	)
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	v := url.Values{}
 	if *force {
@@ -1040,14 +1084,18 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
 	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image")
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 
 	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
 	if err != nil {
@@ -1098,14 +1146,18 @@ func (cli *DockerCli) CmdRm(args ...string) error {
 	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
 	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
 	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	val := url.Values{}
 	if *v {
@@ -1136,14 +1188,18 @@ func (cli *DockerCli) CmdRm(args ...string) error {
 func (cli *DockerCli) CmdKill(args ...string) error {
 	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
 	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	var encounteredError error
 	for _, name := range cmd.Args() {
@@ -1159,15 +1215,18 @@ func (cli *DockerCli) CmdKill(args ...string) error {
 
 func (cli *DockerCli) CmdImport(args ...string) error {
 	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
-
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 	var (
 		v          = url.Values{}
 		src        = cmd.Arg(0)
@@ -1201,15 +1260,19 @@ func (cli *DockerCli) CmdImport(args ...string) error {
 
 func (cli *DockerCli) CmdPush(args ...string) error {
 	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	name := cmd.Arg(0)
-
-	if name == "" {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
+	name := cmd.Arg(0)
 
 	cli.LoadConfigFile()
 
@@ -1267,14 +1330,19 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 func (cli *DockerCli) CmdPull(args ...string) error {
 	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
 	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 	var (
 		v         = url.Values{}
 		remote    = cmd.Arg(0)
@@ -1338,6 +1406,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
 	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
 	flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
 	flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	flFilter := opts.NewListOpts(nil)
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
@@ -1345,10 +1414,13 @@ func (cli *DockerCli) CmdImages(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() > 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Max, 1) {
+		os.Exit(1)
+	}
 
 	// Consolidate all filter flags, and sanity check them early.
 	// They'll get process in the daemon/server.
@@ -1578,6 +1650,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
 		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
 		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
+		help     = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
 		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
 		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
@@ -1591,7 +1664,10 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
+	if *help {
+		cmd.Usage()
+		return nil
+	}
 	if *last == -1 && *nLatest {
 		*last = 1
 	}
@@ -1732,20 +1808,28 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
 	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
 	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
 	flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
+	if *help {
+		cmd.Usage()
+		return nil
+	}
+
+	if cmd.BadArgs(flag.Max, 2) {
+		os.Exit(1)
+	}
+
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	var (
 		name            = cmd.Arg(0)
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
 	)
 
-	if name == "" || len(cmd.Args()) > 2 {
-		cmd.Usage()
-		return nil
-	}
-
 	//Check if the given image name can be resolved
 	if repository != "" {
 		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
@@ -1790,18 +1874,21 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
 	cmd := cli.Subcmd("events", "", "Get real time events from the server")
 	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
 	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
-
 	flFilter := opts.NewListOpts(nil)
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 0 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 0) {
+		os.Exit(1)
+	}
+
 	var (
 		v               = url.Values{}
 		loc             = time.FixedZone(time.Now().Zone())
@@ -1849,14 +1936,18 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
 
 func (cli *DockerCli) CmdExport(args ...string) error {
 	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 
 	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
 		return err
@@ -1866,13 +1957,18 @@ func (cli *DockerCli) CmdExport(args ...string) error {
 
 func (cli *DockerCli) CmdDiff(args ...string) error {
 	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 
 	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
 
@@ -1905,16 +2001,20 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
 		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
 		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
 		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
+		help   = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 	name := cmd.Arg(0)
 
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
@@ -1948,16 +2048,19 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
 		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container")
 		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
 		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
+		help    = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 	name := cmd.Arg(0)
 
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
@@ -2027,13 +2130,18 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
 	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
 	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
 	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 1) {
+		os.Exit(1)
+	}
 
 	v := url.Values{}
 	v.Set("term", cmd.Arg(0))
@@ -2079,13 +2187,18 @@ type ports []int
 func (cli *DockerCli) CmdTag(args ...string) error {
 	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
 	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 2 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 2) {
+		os.Exit(1)
+	}
 
 	var (
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
@@ -2158,6 +2271,7 @@ func newCIDFile(path string) (*cidFile, error) {
 	if _, err := os.Stat(path); err == nil {
 		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
 	}
+
 	f, err := os.Create(path)
 	if err != nil {
 		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
@@ -2474,14 +2588,18 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 
 func (cli *DockerCli) CmdCp(args ...string) error {
 	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-
-	if cmd.NArg() != 2 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 2) {
+		os.Exit(1)
+	}
 
 	var copyData engine.Env
 	info := strings.Split(cmd.Arg(0), ":")
@@ -2514,16 +2632,20 @@ func (cli *DockerCli) CmdCp(args ...string) error {
 
 func (cli *DockerCli) CmdSave(args ...string) error {
 	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)")
-	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
 
 	if err := cmd.Parse(args); err != nil {
 		return err
 	}
 
-	if cmd.NArg() < 1 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	var (
 		output io.Writer = cli.out
@@ -2558,15 +2680,18 @@ func (cli *DockerCli) CmdSave(args ...string) error {
 func (cli *DockerCli) CmdLoad(args ...string) error {
 	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 	if err := cmd.Parse(args); err != nil {
 		return err
 	}
-
-	if cmd.NArg() != 0 {
+	if *help {
 		cmd.Usage()
 		return nil
 	}
+	if cmd.BadArgs(flag.Exact, 0) {
+		os.Exit(1)
+	}
 
 	var (
 		input io.Reader = cli.in
@@ -2588,14 +2713,9 @@ func (cli *DockerCli) CmdExec(args ...string) error {
 	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container")
 
 	execConfig, err := runconfig.ParseExec(cmd, args)
-	if err != nil {
-		cmd.Usage()
+	if execConfig.Container == "" || err != nil {
 		return err
 	}
-	if execConfig.Container == "" {
-		cmd.Usage()
-		return nil
-	}
 
 	stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)
 	if err != nil {

+ 4 - 2
docker/flags.go

@@ -36,6 +36,7 @@ var (
 	flLogLevel    = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
 	flEnableCors  = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
 	flTls         = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by --tlsverify flag")
+	flHelp        = flag.Bool([]string{"h", "-help"}, false, "Print usage")
 	flTlsVerify   = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)")
 
 	// these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs
@@ -57,8 +58,9 @@ func init() {
 	opts.HostListVar(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode or connect to in client mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.")
 
 	flag.Usage = func() {
-		fmt.Fprint(os.Stderr, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n")
+		fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n")
 
+		flag.CommandLine.SetOutput(os.Stdout)
 		flag.PrintDefaults()
 
 		help := "\nCommands:\n"
@@ -105,6 +107,6 @@ func init() {
 			help += fmt.Sprintf("    %-10.10s%s\n", command[0], command[1])
 		}
 		help += "\nRun 'docker COMMAND --help' for more information on a command."
-		fmt.Fprintf(os.Stderr, "%s\n", help)
+		fmt.Fprintf(os.Stdout, "%s\n", help)
 	}
 }

+ 4 - 0
docs/man/docker-attach.1.md

@@ -6,6 +6,7 @@ docker-attach - Attach to a running container
 
 # SYNOPSIS
 **docker attach**
+[**--help**]/
 [**--no-stdin**[=*false*]]
 [**--sig-proxy**[=*true*]]
 CONTAINER
@@ -24,6 +25,9 @@ It is forbidden to redirect the standard input of a docker attach command while
 attaching to a tty-enabled container (i.e.: launched with -t`).
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **--no-stdin**=*true*|*false*
    Do not attach STDIN. The default is *false*.
 

+ 4 - 0
docs/man/docker-build.1.md

@@ -6,6 +6,7 @@ docker-build - Build a new image from the source code at PATH
 
 # SYNOPSIS
 **docker build**
+[**--help**]
 [**--force-rm**[=*false*]]
 [**--no-cache**[=*false*]]
 [**-q**|**--quiet**[=*false*]]
@@ -36,6 +37,9 @@ as context.
 **--no-cache**=*true*|*false*
    Do not use cache when building the image. The default is *false*.
 
+**--help**
+  Print usage statement
+
 **-q**, **--quiet**=*true*|*false*
    Suppress the verbose output generated by the containers. The default is *false*.
 

+ 4 - 0
docs/man/docker-commit.1.md

@@ -7,6 +7,7 @@ docker-commit - Create a new image from a container's changes
 # SYNOPSIS
 **docker commit**
 [**-a**|**--author**[=*AUTHOR*]]
+[**--help**]
 [**-m**|**--message**[=*MESSAGE*]]
 [**-p**|**--pause**[=*true*]]
 CONTAINER [REPOSITORY[:TAG]]
@@ -18,6 +19,9 @@ Using an existing container's name or ID you can create a new image.
 **-a**, **--author**=""
    Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
 
+**--help**
+  Print usage statement
+
 **-m**, **--message**=""
    Commit message
 

+ 3 - 1
docs/man/docker-cp.1.md

@@ -6,6 +6,7 @@ docker-cp - Copy files/folders from the PATH to the HOSTPATH
 
 # SYNOPSIS
 **docker cp**
+[**--help**]
 CONTAINER:PATH HOSTPATH
 
 # DESCRIPTION
@@ -14,7 +15,8 @@ path. Paths are relative to the root of the filesystem. Files
 can be copied from a running or stopped container.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 An important shell script file, created in a bash shell, is copied from

+ 4 - 0
docs/man/docker-create.1.md

@@ -21,6 +21,7 @@ docker-create - Create a new container
 [**--env-file**[=*[]*]]
 [**--expose**[=*[]*]]
 [**-h**|**--hostname**[=*HOSTNAME*]]
+[**--help**]
 [**-i**|**--interactive**[=*false*]]
 [**--ipc**[=*IPC*]]
 [**--link**[=*[]*]]
@@ -87,6 +88,9 @@ IMAGE [COMMAND] [ARG...]
 **-h**, **--hostname**=""
    Container host name
 
+**--help**
+  Print usage statement
+
 **-i**, **--interactive**=*true*|*false*
    Keep STDIN open even if not attached. The default is *false*.
 

+ 3 - 1
docs/man/docker-diff.1.md

@@ -6,6 +6,7 @@ docker-diff - Inspect changes on a container's filesystem
 
 # SYNOPSIS
 **docker diff**
+[**--help**]
 CONTAINER
 
 # DESCRIPTION
@@ -14,7 +15,8 @@ shortened container ID or the container name set using
 **docker run --name** option.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 Inspect the changes to on a nginx container:

+ 4 - 0
docs/man/docker-events.1.md

@@ -6,6 +6,7 @@ docker-events - Get real time events from the server
 
 # SYNOPSIS
 **docker events**
+[**--help**]
 [**--since**[=*SINCE*]]
 [**--until**[=*UNTIL*]]
 
@@ -23,6 +24,9 @@ and Docker images will report:
     untag, delete
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **--since**=""
    Show all events created since timestamp
 

+ 4 - 0
docs/man/docker-exec.1.md

@@ -7,6 +7,7 @@ docker-exec - Run a command in a running container
 # SYNOPSIS
 **docker exec**
 [**-d**|**--detach**[=*false*]]
+[**--help**]
 [**-i**|**--interactive**[=*false*]]
 [**-t**|**--tty**[=*false*]]
 CONTAINER COMMAND [ARG...]
@@ -25,6 +26,9 @@ container is unpaused, and then run
 **-d**, **--detach**=*true*|*false*
    Detached mode: run command in the background. The default is *false*.
 
+**--help**
+  Print usage statement
+
 **-i**, **--interactive**=*true*|*false*
    Keep STDIN open even if not attached. The default is *false*.
 

+ 3 - 1
docs/man/docker-export.1.md

@@ -6,6 +6,7 @@ docker-export - Export the contents of a filesystem as a tar archive to STDOUT
 
 # SYNOPSIS
 **docker export**
+[**--help**]
 CONTAINER
 
 # DESCRIPTION
@@ -14,7 +15,8 @@ container ID or container name. The output is exported to STDOUT and can be
 redirected to a tar file.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 Export the contents of the container called angry_bell to a tar file

+ 4 - 0
docs/man/docker-history.1.md

@@ -6,6 +6,7 @@ docker-history - Show the history of an image
 
 # SYNOPSIS
 **docker history**
+[**--help**]
 [**--no-trunc**[=*false*]]
 [**-q**|**--quiet**[=*false*]]
 IMAGE
@@ -15,6 +16,9 @@ IMAGE
 Show the history of when and how an image was created.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **--no-trunc**=*true*|*false*
    Don't truncate output. The default is *false*.
 

+ 4 - 0
docs/man/docker-images.1.md

@@ -6,6 +6,7 @@ docker-images - List images
 
 # SYNOPSIS
 **docker images**
+[**--help**]
 [**-a**|**--all**[=*false*]]
 [**-f**|**--filter**[=*[]*]]
 [**--no-trunc**[=*false*]]
@@ -35,6 +36,9 @@ versions.
 **-f**, **--filter**=[]
    Provide filter values (i.e. 'dangling=true')
 
+**--help**
+  Print usage statement
+
 **--no-trunc**=*true*|*false*
    Don't truncate output. The default is *false*.
 

+ 3 - 1
docs/man/docker-import.1.md

@@ -6,6 +6,7 @@ docker-import - Create an empty filesystem image and import the contents of the
 
 # SYNOPSIS
 **docker import**
+[**--help**]
 URL|- [REPOSITORY[:TAG]]
 
 # DESCRIPTION
@@ -13,7 +14,8 @@ Create a new filesystem image from the contents of a tarball (`.tar`,
 `.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 

+ 3 - 1
docs/man/docker-info.1.md

@@ -6,6 +6,7 @@ docker-info - Display system-wide information
 
 # SYNOPSIS
 **docker info**
+[**--help**]
 
 
 # DESCRIPTION
@@ -20,7 +21,8 @@ allocates a certain amount of data space and meta data space from the space
 available on the volume where `/var/lib/docker` is mounted.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 

+ 4 - 0
docs/man/docker-inspect.1.md

@@ -6,6 +6,7 @@ docker-inspect - Return low-level information on a container or image
 
 # SYNOPSIS
 **docker inspect**
+[**--help**]
 [**-f**|**--format**[=*FORMAT*]]
 CONTAINER|IMAGE [CONTAINER|IMAGE...]
 
@@ -17,6 +18,9 @@ array. If a format is specified, the given template will be executed for
 each result.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-f**, **--format**=""
    Format the output using the given go template.
 

+ 4 - 0
docs/man/docker-kill.1.md

@@ -6,6 +6,7 @@ docker-kill - Kill a running container using SIGKILL or a specified signal
 
 # SYNOPSIS
 **docker kill**
+[**--help**]
 [**-s**|**--signal**[=*"KILL"*]]
 CONTAINER [CONTAINER...]
 
@@ -15,6 +16,9 @@ The main process inside each container specified will be sent SIGKILL,
  or any signal specified with option --signal.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-s**, **--signal**="KILL"
    Signal to send to the container
 

+ 4 - 0
docs/man/docker-load.1.md

@@ -6,6 +6,7 @@ docker-load - Load an image from a tar archive on STDIN
 
 # SYNOPSIS
 **docker load**
+[**--help**]
 [**-i**|**--input**[=*INPUT*]]
 
 
@@ -15,6 +16,9 @@ Loads a tarred repository from a file or the standard input stream.
 Restores both images and tags.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-i**, **--input**=""
    Read from a tar archive file, instead of STDIN
 

+ 4 - 0
docs/man/docker-login.1.md

@@ -7,6 +7,7 @@ docker-login - Register or log in to a Docker registry server, if no server is s
 # SYNOPSIS
 **docker login**
 [**-e**|**--email**[=*EMAIL*]]
+[**--help**]
 [**-p**|**--password**[=*PASSWORD*]]
 [**-u**|**--username**[=*USERNAME*]]
 [SERVER]
@@ -20,6 +21,9 @@ login to a private registry you can specify this by adding the server name.
 **-e**, **--email**=""
    Email
 
+**--help**
+  Print usage statement
+
 **-p**, **--password**=""
    Password
 

+ 4 - 0
docs/man/docker-logs.1.md

@@ -7,6 +7,7 @@ docker-logs - Fetch the logs of a container
 # SYNOPSIS
 **docker logs**
 [**-f**|**--follow**[=*false*]]
+[**--help**]
 [**-t**|**--timestamps**[=*false*]]
 [**--tail**[=*"all"*]]
 CONTAINER
@@ -22,6 +23,9 @@ The **docker logs --follow** command combines commands **docker logs** and
 then continue streaming new output from the container’s stdout and stderr.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-f**, **--follow**=*true*|*false*
    Follow log output. The default is *false*.
 

+ 3 - 1
docs/man/docker-port.1.md

@@ -6,13 +6,15 @@ docker-port - List port mappings for the CONTAINER, or lookup the public-facing
 
 # SYNOPSIS
 **docker port**
+[**--help**]
 CONTAINER [PRIVATE_PORT[/PROTO]]
 
 # DESCRIPTION
 List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or

+ 4 - 0
docs/man/docker-ps.1.md

@@ -8,6 +8,7 @@ docker-ps - List containers
 **docker ps**
 [**-a**|**--all**[=*false*]]
 [**--before**[=*BEFORE*]]
+[**--help**]
 [**-f**|**--filter**[=*[]*]]
 [**-l**|**--latest**[=*false*]]
 [**-n**[=*-1*]]
@@ -29,6 +30,9 @@ the running containers.
 **--before**=""
    Show only container created before Id or Name, include non-running ones.
 
+**--help**
+  Print usage statement
+
 **-f**, **--filter**=[]
    Provide filter values. Valid filters:
                           exited=<int> - containers with exit code of <int>

+ 4 - 1
docs/man/docker-pull.1.md

@@ -7,6 +7,7 @@ docker-pull - Pull an image or a repository from the registry
 # SYNOPSIS
 **docker pull**
 [**-a**|**--all-tags**[=*false*]]
+[**--help**] 
 NAME[:TAG]
 
 # DESCRIPTION
@@ -19,8 +20,10 @@ It is also possible to specify a non-default registry to pull from.
 # OPTIONS
 **-a**, **--all-tags**=*true*|*false*
    Download all tagged images in the repository. The default is *false*.
+**--help**
+  Print usage statement
 
-# EXAMPLES
+# EXAMPLE
 
 # Pull a repository with multiple images
 # Note that if the  image is previously downloaded then the status would be

+ 3 - 1
docs/man/docker-push.1.md

@@ -6,6 +6,7 @@ docker-push - Push an image or a repository to the registry
 
 # SYNOPSIS
 **docker push**
+[**--help**]
 NAME[:TAG]
 
 # DESCRIPTION
@@ -15,7 +16,8 @@ image can be pushed to another, perhaps private, registry as demonstrated in
 the example below.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 

+ 4 - 0
docs/man/docker-restart.1.md

@@ -6,6 +6,7 @@ docker-restart - Restart a running container
 
 # SYNOPSIS
 **docker restart**
+[**--help**]
 [**-t**|**--time**[=*10*]]
 CONTAINER [CONTAINER...]
 
@@ -13,6 +14,9 @@ CONTAINER [CONTAINER...]
 Restart each container listed.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-t**, **--time**=10
    Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.
 

+ 3 - 0
docs/man/docker-rm.1.md

@@ -19,6 +19,9 @@ remove a running container unless you use the \fB-f\fR option. To see all
 containers on a host use the **docker ps -a** command.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-f**, **--force**=*true*|*false*
    Force the removal of a running container (uses SIGKILL). The default is *false*.
 

+ 4 - 0
docs/man/docker-rmi.1.md

@@ -7,6 +7,7 @@ docker-rmi - Remove one or more images
 # SYNOPSIS
 **docker rmi**
 [**-f**|**--force**[=*false*]]
+[**--help**]
 [**--no-prune**[=*false*]]
 IMAGE [IMAGE...]
 
@@ -21,6 +22,9 @@ use the **docker images** command.
 **-f**, **--force**=*true*|*false*
    Force removal of the image. The default is *false*.
 
+**--help**
+  Print usage statement
+
 **--no-prune**=*true*|*false*
    Do not delete untagged parents. The default is *false*.
 

+ 4 - 0
docs/man/docker-run.1.md

@@ -22,6 +22,7 @@ docker-run - Run a command in a new container
 [**--env-file**[=*[]*]]
 [**--expose**[=*[]*]]
 [**-h**|**--hostname**[=*HOSTNAME*]]
+[**--help**]
 [**-i**|**--interactive**[=*false*]]
 [**--ipc**[=*IPC*]]
 [**--link**[=*[]*]]
@@ -153,6 +154,9 @@ ENTRYPOINT.
 
    Sets the container host name that is available inside the container.
 
+**--help**
+  Print usage statement
+
 **-i**, **--interactive**=*true*|*false*
    Keep STDIN open even if not attached. The default is *false*.
 

+ 4 - 0
docs/man/docker-save.1.md

@@ -6,6 +6,7 @@ docker-save - Save an image(s) to a tar archive (streamed to STDOUT by default)
 
 # SYNOPSIS
 **docker save**
+[**--help**]
 [**-o**|**--output**[=*OUTPUT*]]
 IMAGE [IMAGE...]
 
@@ -16,6 +17,9 @@ parent layers, and all tags + versions, or specified repo:tag.
 Stream to a file instead of STDOUT by using **-o**.
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-o**, **--output**=""
    Write to a file, instead of STDOUT
 

+ 4 - 0
docs/man/docker-search.1.md

@@ -7,6 +7,7 @@ docker-search - Search the Docker Hub for images
 # SYNOPSIS
 **docker search**
 [**--automated**[=*false*]]
+[**--help**]
 [**--no-trunc**[=*false*]]
 [**-s**|**--stars**[=*0*]]
 TERM
@@ -22,6 +23,9 @@ is automated.
 **--automated**=*true*|*false*
    Only show automated builds. The default is *false*.
 
+**--help**
+  Print usage statement
+
 **--no-trunc**=*true*|*false*
    Don't truncate output. The default is *false*.
 

+ 4 - 0
docs/man/docker-start.1.md

@@ -7,6 +7,7 @@ docker-start - Restart a stopped container
 # SYNOPSIS
 **docker start**
 [**-a**|**--attach**[=*false*]]
+[**--help**]
 [**-i**|**--interactive**[=*false*]]
 CONTAINER [CONTAINER...]
 
@@ -18,6 +19,9 @@ Start a stopped container.
 **-a**, **--attach**=*true*|*false*
    Attach container's STDOUT and STDERR and forward all signals to the process. The default is *false*.
 
+**--help**
+  Print usage statement
+
 **-i**, **--interactive**=*true*|*false*
    Attach container's STDIN. The default is *false*.
 

+ 4 - 0
docs/man/docker-stop.1.md

@@ -6,6 +6,7 @@ docker-stop - Stop a running container by sending SIGTERM and then SIGKILL after
 
 # SYNOPSIS
 **docker stop**
+[**--help**]
 [**-t**|**--time**[=*10*]]
 CONTAINER [CONTAINER...]
 
@@ -14,6 +15,9 @@ Stop a running container (Send SIGTERM, and then SIGKILL after
  grace period)
 
 # OPTIONS
+**--help**
+  Print usage statement
+
 **-t**, **--time**=10
    Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.
 

+ 1 - 0
docs/man/docker-tag.1.md

@@ -7,6 +7,7 @@ docker-tag - Tag an image into a repository
 # SYNOPSIS
 **docker tag**
 [**-f**|**--force**[=*false*]]
+[**--help**]
 IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
 
 # DESCRIPTION

+ 3 - 1
docs/man/docker-top.1.md

@@ -6,6 +6,7 @@ docker-top - Display the running processes of a container
 
 # SYNOPSIS
 **docker top**
+[**--help**]
 CONTAINER [ps OPTIONS]
 
 # DESCRIPTION
@@ -14,7 +15,8 @@ Look up the running process of the container. ps-OPTION can be any of the
  options you would pass to a Linux ps command.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 

+ 3 - 1
docs/man/docker-wait.1.md

@@ -6,6 +6,7 @@ docker-wait - Block until a container stops, then print its exit code.
 
 # SYNOPSIS
 **docker wait**
+[**--help**]
 CONTAINER [CONTAINER...]
 
 # DESCRIPTION
@@ -13,7 +14,8 @@ CONTAINER [CONTAINER...]
 Block until a container stops, then print its exit code.
 
 # OPTIONS
-There are no available options.
+**--help**
+  Print usage statement
 
 # EXAMPLES
 

+ 3 - 0
docs/man/docker.1.md

@@ -26,6 +26,9 @@ To see the man page for a command run **man docker <command>**.
 **-D**=*true*|*false*
    Enable debug mode. Default is false.
 
+**--help**
+  Print usage statement
+
 **-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host:port] to bind or
 unix://[/path/to/socket] to use.
    The socket(s) to bind to in daemon mode specified using one or more

+ 13 - 0
docs/sources/reference/commandline/cli.md

@@ -15,6 +15,19 @@ or execute `docker help`:
 
       ...
 
+## Help
+To list the help on any command just execute the command, followed by the `--help` option.
+
+    $ sudo docker run --help
+
+    Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+
+    Run a command in a new container
+
+      -a, --attach=[]            Attach to STDIN, STDOUT or STDERR.
+      -c, --cpu-shares=0         CPU shares (relative weight)
+    ...
+
 ## Option types
 
 Single character commandline options can be combined, so rather than

+ 43 - 2
pkg/mflag/flag.go

@@ -410,6 +410,47 @@ func IsSet(name string) bool {
 	return CommandLine.IsSet(name)
 }
 
+// Indicator used to pass to BadArgs function
+const (
+	Exact = 1
+	Max   = 2
+	Min   = 3
+)
+
+// Bad Args takes two arguments.
+// The first one indicates whether the number of arguments should, be
+// A Minimal number of arguments, a maximum number of arguments or
+// The exact number of arguments required
+// If the actuall number of arguments is not valid and error message
+// prints and true is returned, otherwise false is returned
+func (f *FlagSet) BadArgs(arg_type, nargs int) bool {
+	if arg_type == Max && f.NArg() > nargs {
+		if nargs == 1 {
+			fmt.Fprintf(f.out(), "docker: '%s' requires a maximum of 1 argument. See 'docker %s --help'.\n", f.name, f.name)
+		} else {
+			fmt.Fprintf(f.out(), "docker: '%s' requires a maximum of %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
+		}
+		return true
+	}
+	if arg_type == Exact && f.NArg() != nargs {
+		if nargs == 1 {
+			fmt.Fprintf(f.out(), "docker: '%s' requires 1 argument. See 'docker %s --help'.\n", f.name, f.name)
+		} else {
+			fmt.Fprintf(f.out(), "docker: '%s' requires %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
+		}
+		return true
+	}
+	if arg_type == Min && f.NArg() < nargs {
+		if nargs == 1 {
+			fmt.Fprintf(f.out(), "docker: '%s' requires a minimum of 1 argument. See 'docker %s --help'.\n", f.name, f.name)
+		} else {
+			fmt.Fprintf(f.out(), "docker: '%s' requires a minimum of %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
+		}
+		return true
+	}
+	return false
+}
+
 // Set sets the value of the named flag.
 func (f *FlagSet) Set(name, value string) error {
 	flag, ok := f.formal[name]
@@ -483,7 +524,7 @@ func defaultUsage(f *FlagSet) {
 // Usage prints to standard error a usage message documenting all defined command-line flags.
 // The function is a variable that may be changed to point to a custom function.
 var Usage = func() {
-	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+	fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0])
 	PrintDefaults()
 }
 
@@ -789,7 +830,7 @@ func Var(value Value, names []string, usage string) {
 func (f *FlagSet) failf(format string, a ...interface{}) error {
 	err := fmt.Errorf(format, a...)
 	fmt.Fprintln(f.out(), err)
-	f.usage()
+	fmt.Fprintf(f.out(), "See 'docker %s --help'.\n", f.name)
 	return err
 }
 

+ 9 - 3
runconfig/exec.go

@@ -5,6 +5,7 @@ import (
 
 	"github.com/docker/docker/engine"
 	flag "github.com/docker/docker/pkg/mflag"
+	"os"
 )
 
 type ExecConfig struct {
@@ -45,17 +46,22 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
 		flStdin   = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
 		flTty     = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
 		flDetach  = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
+		help      = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 		execCmd   []string
 		container string
 	)
 	if err := cmd.Parse(args); err != nil {
 		return nil, err
 	}
-	parsedArgs := cmd.Args()
-	if len(parsedArgs) < 2 {
-		return nil, fmt.Errorf("not enough arguments to create exec command")
+	if *help {
+		cmd.Usage()
+		return nil, nil
+	}
+	if cmd.BadArgs(flag.Min, 2) {
+		os.Exit(1)
 	}
 	container = cmd.Arg(0)
+	parsedArgs := cmd.Args()
 	execCmd = parsedArgs[1:]
 
 	execConfig := &ExecConfig{

+ 10 - 4
runconfig/parse.go

@@ -2,6 +2,7 @@ package runconfig
 
 import (
 	"fmt"
+	"os"
 	"path"
 	"strconv"
 	"strings"
@@ -61,6 +62,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 		flMacAddress      = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
 		flIpcMode         = cmd.String([]string{"-ipc"}, "", "Default is to create a private IPC namespace (POSIX SysV IPC) for the container\n'container:<name|id>': reuses another container shared memory, semaphores and message queues\n'host': use the host shared memory,semaphores and message queues inside the container.  Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.")
 		flRestartPolicy   = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
+		help              = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 
 	cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
@@ -86,6 +88,13 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 	if err := cmd.Parse(args); err != nil {
 		return nil, nil, cmd, err
 	}
+	if *help {
+		cmd.Usage()
+		return nil, nil, cmd, nil
+	}
+	if cmd.BadArgs(flag.Min, 1) {
+		os.Exit(1)
+	}
 
 	// Validate input params
 	if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
@@ -156,11 +165,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 		parsedArgs = cmd.Args()
 		runCmd     []string
 		entrypoint []string
-		image      string
+		image      = cmd.Arg(0)
 	)
-	if len(parsedArgs) >= 1 {
-		image = cmd.Arg(0)
-	}
 	if len(parsedArgs) > 1 {
 		runCmd = parsedArgs[1:]
 	}