Skip to content

Implement multiple command parsing (docker style)

Lloyd Brookes edited this page Jan 25, 2018 · 5 revisions

We can use stopAtFirstUnknown to parse an input argv array several times, making complex scenarios possible.

As an example we'll recreate the docker run command. The command line syntax for docker accepts not one but multiple commands, in this form.

$ docker <command> [options] <image> <sub-command> [options]

Example

This is the full example script. After each commandLineArgs() invocation, the _unknown list is used as input to the next invocation.

const commandLineArgs = require('command-line-args')

/* first - parse the main command name */
let mainDefinitions = [
  { name: 'name', defaultOption: true }
]
const mainCommand = commandLineArgs(mainDefinitions, { stopAtFirstUnknown: true })
let argv = mainCommand._unknown || []

console.log('mainCommand\n===========')
console.log(mainCommand)

/* second - parse the main command options */
if (mainCommand.name === 'run') {
  const runDefinitions = [
    { name: 'detached', alias: 'd', type: Boolean },
    { name: 'target', defaultOption: true }
  ]
  const runOptions = commandLineArgs(runDefinitions, { argv, stopAtFirstUnknown: true })
  argv = runOptions._unknown || []

  console.log('\nrunOptions\n==========')
  console.log(runOptions)

  /* third - parse the sub-command  */
  const subCommandDefinitions = [
    { name: 'name', defaultOption: true }
  ]
  const subCommand = commandLineArgs(subCommandDefinitions, { argv, stopAtFirstUnknown: true })

  console.log('\nsubCommand\n==========')
  console.log(subCommand)
}

Running this command produces the following output.

$ node example.js run -d centos bash -c yum install -y httpd
mainCommand
===========
{ _unknown: [ '-d', 'centos', 'bash', '-c', 'yum', 'install', '-y', 'httpd' ],
  name: 'run' }

runOptions
==========
{ _unknown: [ 'bash', '-c', 'yum', 'install', '-y', 'httpd' ],
  detached: true,
  target: 'centos' }

subCommand
==========
{ _unknown: [ '-c', 'yum', 'install', '-y', 'httpd' ],
  name: 'bash' }