clk

A very opinionated framework to ease the creation of command line interfaces

View on GitHub

An option is an optional parameter that is given a value. A flag is an optional parameter that is a boolean. An argument is a positional parameter that you must give.

A:kind-of-animal:$(clk_format_choice duck whale cat dog):A kind of animal:{"default": "duck", "nargs": 1}
O:--sound-of-animal:str:The sound the animal makes
O:--repeat:int:How many times to repeat the message:0
F:--shout:Print the message of the animal in capital case
if clk_given sound-of-animal
then
    msg="$(clk_value kind-of-animal) does $(clk_value sound-of-animal)"
else
    msg="I don't know what sound ${CLK___KIND_OF_ANIMAL} makes"
fi

if clk_true shout
then
    echo "${msg}"|tr '[:lower:]' '[:upper:]'
else
    echo "${msg}"
fi

for i in $(seq 1 "${CLK___REPEAT}")
do
    echo "${msg}"
done
clk command create bash animal --no-open
cat <<"EOH" > "$(clk command which animal)"
#!/usr/bin/env bash
set -eu

source "_clk.sh"

clk_usage () {
    cat<<EOF
$0

This command shows something
--
A:kind-of-animal:$(clk_format_choice duck whale cat dog):A kind of animal:{"default": "duck", "nargs": 1}
O:--sound-of-animal:str:The sound the animal makes
O:--repeat:int:How many times to repeat the message:0
F:--shout:Print the message of the animal in capital case
EOF
}

clk_help_handler "$@"

if clk_given sound-of-animal
then
    msg="$(clk_value kind-of-animal) does $(clk_value sound-of-animal)"
else
    msg="I don't know what sound ${CLK___KIND_OF_ANIMAL} makes"
fi

if clk_true shout
then
    echo "${msg}"|tr '[:lower:]' '[:upper:]'
else
    echo "${msg}"
fi

for i in $(seq 1 "${CLK___REPEAT}")
do
    echo "${msg}"
done

EOH

We can see the help of those parameters in the help of the command.

clk animal --help | grep -- 'KIND_OF_ANIMAL'
clk animal --help | grep -- '--sound-of-animal'
clk animal --help | grep -- '--repeat'
clk animal --help | grep -- '--shout'
KIND_OF_ANIMAL [duck|whale|cat|dog]
--sound-of-animal TEXT  The sound the animal makes  [default: None]
--repeat INTEGER        How many times to repeat the message  [default: 0]
--shout                 Print the message of the animal in capital case  [default: False]

completing against files

Sometimes, your command takes a file as input. For instance, let’s say you want a command that counts the words in a document.

You want pressing <TAB> on the argument to suggest files from the current directory, just like cat or ls would. To get this, use the file type.

A:document:file:The document to count words in
clk command create bash wordcount
cat <<"EOH" > "$(clk command which wordcount)"
#!/usr/bin/env bash
set -eu

source "_clk.sh"

clk_usage () {
    cat<<EOF
$0

Count the words in a document
--
A:document:file:The document to count words in
EOF
}

clk_help_handler "$@"

wc -w < "$(clk_value document)"

EOH
clk wordcount --help | grep DOCUMENT
Usage: clk wordcount [OPTIONS] [DOCUMENT]
  DOCUMENT  The document to count words in  [default: None]

Let’s try it.

echo "one two three four five" > testfile.txt
clk wordcount testfile.txt
5

And completion suggests files from the current directory.

clk wordcount te<TAB>
./testfile.txt

The file type works the same way for options. For instance, if you had written O:--document:file:The document to count words in instead, pressing <TAB> after --document would also suggest files.

passing a URL to a file argument

Sometimes, a command argument declared with the file type may also accept a URL. For instance, a command that installs a package might accept either a local file path or a URL to download from.

A:package:file:Package to install
echo "$(clk_value package)"

When passing a URL, the value should be preserved as-is, without being resolved as a file path.

clk showpackage https://example.com/path/to/package.apk
https://example.com/path/to/package.apk