Convert inspect command to Cobra
| ... | ... |
@@ -2,7 +2,5 @@ package client |
| 2 | 2 |
|
| 3 | 3 |
// Command returns a cli command handler if one exists |
| 4 | 4 |
func (cli *DockerCli) Command(name string) func(...string) error {
|
| 5 |
- return map[string]func(...string) error{
|
|
| 6 |
- "inspect": cli.CmdInspect, |
|
| 7 |
- }[name] |
|
| 5 |
+ return map[string]func(...string) error{}[name]
|
|
| 8 | 6 |
} |
| 9 | 7 |
deleted file mode 100644 |
| ... | ... |
@@ -1,95 +0,0 @@ |
| 1 |
-package client |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- |
|
| 6 |
- "golang.org/x/net/context" |
|
| 7 |
- |
|
| 8 |
- "github.com/docker/docker/api/client/inspect" |
|
| 9 |
- Cli "github.com/docker/docker/cli" |
|
| 10 |
- flag "github.com/docker/docker/pkg/mflag" |
|
| 11 |
- "github.com/docker/engine-api/client" |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-// CmdInspect displays low-level information on one or more containers, images or tasks. |
|
| 15 |
-// |
|
| 16 |
-// Usage: docker inspect [OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...] |
|
| 17 |
-func (cli *DockerCli) CmdInspect(args ...string) error {
|
|
| 18 |
- cmd := Cli.Subcmd("inspect", []string{"[OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...]"}, Cli.DockerCommands["inspect"].Description, true)
|
|
| 19 |
- tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
|
| 20 |
- inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image, container or task)")
|
|
| 21 |
- size := cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes if the type is container")
|
|
| 22 |
- cmd.Require(flag.Min, 1) |
|
| 23 |
- |
|
| 24 |
- cmd.ParseFlags(args, true) |
|
| 25 |
- |
|
| 26 |
- if *inspectType != "" && *inspectType != "container" && *inspectType != "image" && *inspectType != "task" {
|
|
| 27 |
- return fmt.Errorf("%q is not a valid value for --type", *inspectType)
|
|
| 28 |
- } |
|
| 29 |
- |
|
| 30 |
- ctx := context.Background() |
|
| 31 |
- |
|
| 32 |
- var elementSearcher inspect.GetRefFunc |
|
| 33 |
- switch *inspectType {
|
|
| 34 |
- case "container": |
|
| 35 |
- elementSearcher = cli.inspectContainers(ctx, *size) |
|
| 36 |
- case "image": |
|
| 37 |
- elementSearcher = cli.inspectImages(ctx, *size) |
|
| 38 |
- case "task": |
|
| 39 |
- if *size {
|
|
| 40 |
- fmt.Fprintln(cli.err, "WARNING: --size ignored for tasks") |
|
| 41 |
- } |
|
| 42 |
- elementSearcher = cli.inspectTasks(ctx) |
|
| 43 |
- default: |
|
| 44 |
- elementSearcher = cli.inspectAll(ctx, *size) |
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
- return inspect.Inspect(cli.out, cmd.Args(), *tmplStr, elementSearcher) |
|
| 48 |
-} |
|
| 49 |
- |
|
| 50 |
-func (cli *DockerCli) inspectContainers(ctx context.Context, getSize bool) inspect.GetRefFunc {
|
|
| 51 |
- return func(ref string) (interface{}, []byte, error) {
|
|
| 52 |
- return cli.client.ContainerInspectWithRaw(ctx, ref, getSize) |
|
| 53 |
- } |
|
| 54 |
-} |
|
| 55 |
- |
|
| 56 |
-func (cli *DockerCli) inspectImages(ctx context.Context, getSize bool) inspect.GetRefFunc {
|
|
| 57 |
- return func(ref string) (interface{}, []byte, error) {
|
|
| 58 |
- return cli.client.ImageInspectWithRaw(ctx, ref, getSize) |
|
| 59 |
- } |
|
| 60 |
-} |
|
| 61 |
- |
|
| 62 |
-func (cli *DockerCli) inspectTasks(ctx context.Context) inspect.GetRefFunc {
|
|
| 63 |
- return func(ref string) (interface{}, []byte, error) {
|
|
| 64 |
- return cli.client.TaskInspectWithRaw(ctx, ref) |
|
| 65 |
- } |
|
| 66 |
-} |
|
| 67 |
- |
|
| 68 |
-func (cli *DockerCli) inspectAll(ctx context.Context, getSize bool) inspect.GetRefFunc {
|
|
| 69 |
- return func(ref string) (interface{}, []byte, error) {
|
|
| 70 |
- c, rawContainer, err := cli.client.ContainerInspectWithRaw(ctx, ref, getSize) |
|
| 71 |
- if err != nil {
|
|
| 72 |
- // Search for image with that id if a container doesn't exist. |
|
| 73 |
- if client.IsErrContainerNotFound(err) {
|
|
| 74 |
- i, rawImage, err := cli.client.ImageInspectWithRaw(ctx, ref, getSize) |
|
| 75 |
- if err != nil {
|
|
| 76 |
- if client.IsErrImageNotFound(err) {
|
|
| 77 |
- // Search for task with that id if an image doesn't exists. |
|
| 78 |
- t, rawTask, err := cli.client.TaskInspectWithRaw(ctx, ref) |
|
| 79 |
- if err != nil {
|
|
| 80 |
- return nil, nil, fmt.Errorf("Error: No such image, container or task: %s", ref)
|
|
| 81 |
- } |
|
| 82 |
- if getSize {
|
|
| 83 |
- fmt.Fprintln(cli.err, "WARNING: --size ignored for tasks") |
|
| 84 |
- } |
|
| 85 |
- return t, rawTask, nil |
|
| 86 |
- } |
|
| 87 |
- return nil, nil, err |
|
| 88 |
- } |
|
| 89 |
- return i, rawImage, nil |
|
| 90 |
- } |
|
| 91 |
- return nil, nil, err |
|
| 92 |
- } |
|
| 93 |
- return c, rawContainer, nil |
|
| 94 |
- } |
|
| 95 |
-} |
| 96 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,103 @@ |
| 0 |
+package system |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "golang.org/x/net/context" |
|
| 7 |
+ |
|
| 8 |
+ "github.com/docker/docker/api/client" |
|
| 9 |
+ "github.com/docker/docker/api/client/inspect" |
|
| 10 |
+ "github.com/docker/docker/cli" |
|
| 11 |
+ apiclient "github.com/docker/engine-api/client" |
|
| 12 |
+ "github.com/spf13/cobra" |
|
| 13 |
+) |
|
| 14 |
+ |
|
| 15 |
+type inspectOptions struct {
|
|
| 16 |
+ format string |
|
| 17 |
+ inspectType string |
|
| 18 |
+ size bool |
|
| 19 |
+ ids []string |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+// NewInspectCommand creates a new cobra.Command for `docker inspect` |
|
| 23 |
+func NewInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
|
|
| 24 |
+ var opts inspectOptions |
|
| 25 |
+ |
|
| 26 |
+ cmd := &cobra.Command{
|
|
| 27 |
+ Use: "inspect [OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...]", |
|
| 28 |
+ Short: "Return low-level information on a container, image or task", |
|
| 29 |
+ Args: cli.RequiresMinArgs(1), |
|
| 30 |
+ RunE: func(cmd *cobra.Command, args []string) error {
|
|
| 31 |
+ opts.ids = args |
|
| 32 |
+ return runInspect(dockerCli, opts) |
|
| 33 |
+ }, |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ flags := cmd.Flags() |
|
| 37 |
+ flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template") |
|
| 38 |
+ flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type, (e.g image, container or task)") |
|
| 39 |
+ flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container") |
|
| 40 |
+ |
|
| 41 |
+ return cmd |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
|
|
| 45 |
+ ctx := context.Background() |
|
| 46 |
+ client := dockerCli.Client() |
|
| 47 |
+ |
|
| 48 |
+ var getRefFunc inspect.GetRefFunc |
|
| 49 |
+ switch opts.inspectType {
|
|
| 50 |
+ case "container": |
|
| 51 |
+ getRefFunc = func(ref string) (interface{}, []byte, error) {
|
|
| 52 |
+ return client.ContainerInspectWithRaw(ctx, ref, opts.size) |
|
| 53 |
+ } |
|
| 54 |
+ case "image": |
|
| 55 |
+ getRefFunc = func(ref string) (interface{}, []byte, error) {
|
|
| 56 |
+ return client.ImageInspectWithRaw(ctx, ref, opts.size) |
|
| 57 |
+ } |
|
| 58 |
+ case "task": |
|
| 59 |
+ if opts.size {
|
|
| 60 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks") |
|
| 61 |
+ } |
|
| 62 |
+ getRefFunc = func(ref string) (interface{}, []byte, error) {
|
|
| 63 |
+ return client.TaskInspectWithRaw(ctx, ref) |
|
| 64 |
+ } |
|
| 65 |
+ case "": |
|
| 66 |
+ getRefFunc = inspectAll(ctx, dockerCli, opts.size) |
|
| 67 |
+ default: |
|
| 68 |
+ return fmt.Errorf("%q is not a valid value for --type", opts.inspectType)
|
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, getRefFunc) |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
|
|
| 75 |
+ client := dockerCli.Client() |
|
| 76 |
+ |
|
| 77 |
+ return func(ref string) (interface{}, []byte, error) {
|
|
| 78 |
+ c, rawContainer, err := client.ContainerInspectWithRaw(ctx, ref, getSize) |
|
| 79 |
+ if err == nil || !apiclient.IsErrNotFound(err) {
|
|
| 80 |
+ return c, rawContainer, err |
|
| 81 |
+ } |
|
| 82 |
+ // Search for image with that id if a container doesn't exist. |
|
| 83 |
+ i, rawImage, err := client.ImageInspectWithRaw(ctx, ref, getSize) |
|
| 84 |
+ if err == nil || !apiclient.IsErrNotFound(err) {
|
|
| 85 |
+ return i, rawImage, err |
|
| 86 |
+ } |
|
| 87 |
+ |
|
| 88 |
+ // Search for task with that id if an image doesn't exist. |
|
| 89 |
+ t, rawTask, err := client.TaskInspectWithRaw(ctx, ref) |
|
| 90 |
+ if err == nil || !(apiclient.IsErrNotFound(err) || isErrorNoSwarmMode(err)) {
|
|
| 91 |
+ if getSize {
|
|
| 92 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks") |
|
| 93 |
+ } |
|
| 94 |
+ return t, rawTask, err |
|
| 95 |
+ } |
|
| 96 |
+ return nil, nil, fmt.Errorf("Error: No such container, image or task: %s", ref)
|
|
| 97 |
+ } |
|
| 98 |
+} |
|
| 99 |
+ |
|
| 100 |
+func isErrorNoSwarmMode(err error) bool {
|
|
| 101 |
+ return strings.Contains(err.Error(), "This node is not a swarm manager") |
|
| 102 |
+} |
| ... | ... |
@@ -83,6 +83,7 @@ func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor {
|
| 83 | 83 |
image.NewTagCommand(dockerCli), |
| 84 | 84 |
network.NewNetworkCommand(dockerCli), |
| 85 | 85 |
system.NewEventsCommand(dockerCli), |
| 86 |
+ system.NewInspectCommand(dockerCli), |
|
| 86 | 87 |
registry.NewLoginCommand(dockerCli), |
| 87 | 88 |
registry.NewLogoutCommand(dockerCli), |
| 88 | 89 |
system.NewVersionCommand(dockerCli), |
| ... | ... |
@@ -7,9 +7,7 @@ type Command struct {
|
| 7 | 7 |
} |
| 8 | 8 |
|
| 9 | 9 |
// DockerCommandUsage lists the top level docker commands and their short usage |
| 10 |
-var DockerCommandUsage = []Command{
|
|
| 11 |
- {"inspect", "Return low-level information on a container, image or task"},
|
|
| 12 |
-} |
|
| 10 |
+var DockerCommandUsage = []Command{}
|
|
| 13 | 11 |
|
| 14 | 12 |
// DockerCommands stores all the docker command |
| 15 | 13 |
var DockerCommands = make(map[string]Command) |
| ... | ... |
@@ -176,7 +176,7 @@ func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) {
|
| 176 | 176 |
_, err = inspectFieldWithError(imageReference, "Id") |
| 177 | 177 |
//unexpected nil err trying to inspect what should be a non-existent image |
| 178 | 178 |
c.Assert(err, checker.NotNil) |
| 179 |
- c.Assert(err.Error(), checker.Contains, "No such image") |
|
| 179 |
+ c.Assert(err.Error(), checker.Contains, "No such container, image") |
|
| 180 | 180 |
} |
| 181 | 181 |
|
| 182 | 182 |
func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) {
|
| ... | ... |
@@ -326,7 +326,7 @@ func (s *DockerDaemonSuite) TestDaemonIptablesCreate(c *check.C) {
|
| 326 | 326 |
} |
| 327 | 327 |
|
| 328 | 328 |
// make sure the container is not running |
| 329 |
- runningOut, err := s.d.Cmd("inspect", "--format='{{.State.Running}}'", "top")
|
|
| 329 |
+ runningOut, err := s.d.Cmd("inspect", "--format={{.State.Running}}", "top")
|
|
| 330 | 330 |
if err != nil {
|
| 331 | 331 |
c.Fatalf("Could not inspect on container: %s, %v", out, err)
|
| 332 | 332 |
} |
| ... | ... |
@@ -2196,7 +2196,7 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonCrash(c *check.C) {
|
| 2196 | 2196 |
} |
| 2197 | 2197 |
|
| 2198 | 2198 |
// container should be running. |
| 2199 |
- out, err = s.d.Cmd("inspect", "--format='{{.State.Running}}'", id)
|
|
| 2199 |
+ out, err = s.d.Cmd("inspect", "--format={{.State.Running}}", id)
|
|
| 2200 | 2200 |
c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
|
| 2201 | 2201 |
out = strings.TrimSpace(out) |
| 2202 | 2202 |
if out != "true" {
|
| ... | ... |
@@ -353,7 +353,7 @@ func (s *DockerExternalGraphdriverSuite) testExternalGraphDriver(name string, ex |
| 353 | 353 |
|
| 354 | 354 |
err = s.d.Restart("-s", name)
|
| 355 | 355 |
|
| 356 |
- out, err = s.d.Cmd("inspect", "--format='{{.GraphDriver.Name}}'", "graphtest")
|
|
| 356 |
+ out, err = s.d.Cmd("inspect", "--format={{.GraphDriver.Name}}", "graphtest")
|
|
| 357 | 357 |
c.Assert(err, check.IsNil, check.Commentf(out)) |
| 358 | 358 |
c.Assert(strings.TrimSpace(out), check.Equals, name) |
| 359 | 359 |
|
| ... | ... |
@@ -73,10 +73,10 @@ func (s *DockerSuite) TestHealth(c *check.C) {
|
| 73 | 73 |
|
| 74 | 74 |
// Inspect the options |
| 75 | 75 |
out, _ = dockerCmd(c, "inspect", |
| 76 |
- "--format='timeout={{.Config.Healthcheck.Timeout}} "+
|
|
| 76 |
+ "--format=timeout={{.Config.Healthcheck.Timeout}} "+
|
|
| 77 | 77 |
"interval={{.Config.Healthcheck.Interval}} "+
|
| 78 | 78 |
"retries={{.Config.Healthcheck.Retries}} "+
|
| 79 |
- "test={{.Config.Healthcheck.Test}}'", name)
|
|
| 79 |
+ "test={{.Config.Healthcheck.Test}}", name)
|
|
| 80 | 80 |
c.Check(out, checker.Equals, "timeout=30s interval=1s retries=0 test=[CMD-SHELL cat /status]\n") |
| 81 | 81 |
|
| 82 | 82 |
// Start |
| ... | ... |
@@ -85,7 +85,7 @@ func (s *DockerSuite) TestInspectTypeFlagContainer(c *check.C) {
|
| 85 | 85 |
|
| 86 | 86 |
dockerCmd(c, "run", "--name=busybox", "-d", "busybox", "top") |
| 87 | 87 |
|
| 88 |
- formatStr := "--format='{{.State.Running}}'"
|
|
| 88 |
+ formatStr := "--format={{.State.Running}}"
|
|
| 89 | 89 |
out, _ := dockerCmd(c, "inspect", "--type=container", formatStr, "busybox") |
| 90 | 90 |
c.Assert(out, checker.Equals, "true\n") // not a container JSON |
| 91 | 91 |
} |
| ... | ... |
@@ -137,7 +137,7 @@ func (s *DockerSuite) TestInspectImageFilterInt(c *check.C) {
|
| 137 | 137 |
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect size of the image: %s, %v", out, err))
|
| 138 | 138 |
|
| 139 | 139 |
//now see if the size turns out to be the same |
| 140 |
- formatStr := fmt.Sprintf("--format='{{eq .Size %d}}'", size)
|
|
| 140 |
+ formatStr := fmt.Sprintf("--format={{eq .Size %d}}", size)
|
|
| 141 | 141 |
out, _ = dockerCmd(c, "inspect", formatStr, imageTest) |
| 142 | 142 |
result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")) |
| 143 | 143 |
c.Assert(err, checker.IsNil) |
| ... | ... |
@@ -159,7 +159,7 @@ func (s *DockerSuite) TestInspectContainerFilterInt(c *check.C) {
|
| 159 | 159 |
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect exitcode of the container: %s, %v", out, err))
|
| 160 | 160 |
|
| 161 | 161 |
//now get the exit code to verify |
| 162 |
- formatStr := fmt.Sprintf("--format='{{eq .State.ExitCode %d}}'", exitCode)
|
|
| 162 |
+ formatStr := fmt.Sprintf("--format={{eq .State.ExitCode %d}}", exitCode)
|
|
| 163 | 163 |
out, _ = dockerCmd(c, "inspect", formatStr, id) |
| 164 | 164 |
result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")) |
| 165 | 165 |
c.Assert(err, checker.IsNil) |
| ... | ... |
@@ -312,7 +312,7 @@ func (s *DockerSuite) TestInspectNoSizeFlagContainer(c *check.C) {
|
| 312 | 312 |
|
| 313 | 313 |
runSleepingContainer(c, "--name=busybox", "-d") |
| 314 | 314 |
|
| 315 |
- formatStr := "--format='{{.SizeRw}},{{.SizeRootFs}}'"
|
|
| 315 |
+ formatStr := "--format={{.SizeRw}},{{.SizeRootFs}}"
|
|
| 316 | 316 |
out, _ := dockerCmd(c, "inspect", "--type=container", formatStr, "busybox") |
| 317 | 317 |
c.Assert(strings.TrimSpace(out), check.Equals, "<nil>,<nil>", check.Commentf("Exepcted not to display size info: %s", out))
|
| 318 | 318 |
} |
| ... | ... |
@@ -356,7 +356,7 @@ func (s *DockerSuite) TestInspectTemplateError(c *check.C) {
|
| 356 | 356 |
|
| 357 | 357 |
func (s *DockerSuite) TestInspectJSONFields(c *check.C) {
|
| 358 | 358 |
runSleepingContainer(c, "--name=busybox", "-d") |
| 359 |
- out, _, err := dockerCmdWithError("inspect", "--type=container", "--format='{{.HostConfig.Dns}}'", "busybox")
|
|
| 359 |
+ out, _, err := dockerCmdWithError("inspect", "--type=container", "--format={{.HostConfig.Dns}}", "busybox")
|
|
| 360 | 360 |
|
| 361 | 361 |
c.Assert(err, check.IsNil) |
| 362 | 362 |
c.Assert(out, checker.Equals, "[]\n") |
| ... | ... |
@@ -63,7 +63,7 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
|
| 63 | 63 |
|
| 64 | 64 |
name, err := inspectFieldWithError("first_name", "Name")
|
| 65 | 65 |
c.Assert(err, checker.NotNil, check.Commentf(name)) |
| 66 |
- c.Assert(err.Error(), checker.Contains, "No such image, container or task: first_name") |
|
| 66 |
+ c.Assert(err.Error(), checker.Contains, "No such container, image or task: first_name") |
|
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 | 69 |
func (s *DockerSuite) TestRenameInvalidName(c *check.C) {
|
| ... | ... |
@@ -129,7 +129,7 @@ func (s *DockerSuite) TestRenameContainerWithLinkedContainer(c *check.C) {
|
| 129 | 129 |
db1, _ := dockerCmd(c, "run", "--name", "db1", "-d", "busybox", "top") |
| 130 | 130 |
dockerCmd(c, "run", "--name", "app1", "-d", "--link", "db1:/mysql", "busybox", "top") |
| 131 | 131 |
dockerCmd(c, "rename", "app1", "app2") |
| 132 |
- out, _, err := dockerCmdWithError("inspect", "--format='{{ .Id }}'", "app2/mysql")
|
|
| 132 |
+ out, _, err := dockerCmdWithError("inspect", "--format={{ .Id }}", "app2/mysql")
|
|
| 133 | 133 |
c.Assert(err, checker.IsNil) |
| 134 | 134 |
c.Assert(strings.TrimSpace(out), checker.Equals, strings.TrimSpace(db1)) |
| 135 | 135 |
} |
| ... | ... |
@@ -45,7 +45,7 @@ func (s *DockerDaemonSuite) TestDaemonUserNamespaceRootSetting(c *check.C) {
|
| 45 | 45 |
user := s.findUser(c, "userns") |
| 46 | 46 |
c.Assert(uidgid[0], checker.Equals, user) |
| 47 | 47 |
|
| 48 |
- pid, err := s.d.Cmd("inspect", "--format='{{.State.Pid}}'", "userns")
|
|
| 48 |
+ pid, err := s.d.Cmd("inspect", "--format={{.State.Pid}}", "userns")
|
|
| 49 | 49 |
c.Assert(err, checker.IsNil, check.Commentf("Could not inspect running container: out: %q", pid))
|
| 50 | 50 |
// check the uid and gid maps for the PID to ensure root is remapped |
| 51 | 51 |
// (cmd = cat /proc/<pid>/uid_map | grep -E '0\s+9999\s+1') |