c108.cli
CLI command formatting and normalization tools.
cli_multiline(command, *, shlex_split=True, multiline_indent=8, max_line_length=120)
Format a command as a readable multi-line POSIX shell string with line continuations.
This function takes a command (in the same formats as clify()) and formats it as a multi-line string suitable for POSIX-compatible shells (bash, zsh, sh, etc.). Long options (--option) and flags (-f) start new lines for better readability.
Platform Support:
- ✓ Linux, macOS, Unix (bash, zsh, sh, fish, etc.)
- ✓ Windows with WSL, Git Bash, MSYS2, Cygwin
- ✗ Windows Command Prompt (cmd.exe) - uses ^ for continuation
- ✗ Windows PowerShell - uses backtick (`) for continuation
Output Format: Uses POSIX shell line continuation syntax with backslash () at end of lines. The resulting string can be copied directly into POSIX shell scripts or terminals.
Rules: - First argument stays on the first line - Long options (--option, --option=value) start new lines - Short flags (-f, -abc) start new lines - Flag values stay on the same line as their flag - Positional arguments after options start new lines - Line continuations use backslash () - Each continued line is indented by multiline_indent spaces
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
command
|
str | int | float | Iterable[Any] | None
|
Same input types as clify() - string, int, float, iterable, or None. |
required |
shlex_split
|
bool
|
Whether to shell-split string input (same as clify). |
True
|
multiline_indent
|
int
|
Number of spaces to indent continuation lines, int >=0 required. |
8
|
max_line_length
|
int
|
Hint for when to break lines (not strictly enforced), int > 0 required. |
120
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Multi-line formatted POSIX shell command string, or empty string if no command. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If multiline_indent or max_line_length is invalid. |
Examples:
>>> cmd = cli_multiline(['tar', '-cvpzf', 'backup.tar.gz', '--exclude=/proc', '--exclude=/sys'])
>>> # 'tar -cvpzf backup.tar.gz \
>>> # --exclude=/proc \
>>> # --exclude=/sys'
>>> cmd = cli_multiline('git commit -m "Initial commit" --author="John Doe"')
>>> # 'git commit -m "Initial commit" \
>>> # --author="John Doe"'
>>> # The output can be used directly in bash scripts:
>>> cmd = cli_multiline(['docker', 'run', '--rm', '-v', '/data:/data', 'ubuntu:latest'])
>>> # docker run --rm \
>>> # -v /data:/data \
>>> # ubuntu:latest
Note
For Windows cmd.exe or PowerShell compatibility, consider using clify() to get the argument list and format it according to the target shell's line continuation syntax.
Source code in c108/cli.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | |
clify(command, shlex_split=True, *, max_items=256, max_arg_length=4096)
Normalize a command into a subprocess-ready argv list with sanity checks.
This function composes a command—provided as a shell-like string or an iterable of arguments—into a list[str] suitable for subprocess APIs (e.g., subprocess.run).
Rules: - None → []. - String input: - shlex_split=True (default): shell-parse using shlex.split; quotes/escapes respected. - shlex_split=False: treat the entire string as a single argument. - Empty string → []. - Int/float input: converted to string as a single argument. - Iterable input: each item is converted to text for argv: - Path-like objects via os.fspath. - Everything else via str. - The iterable is not recursively flattened; nested iterables are stringified.
Sanity checks: - max_items: maximum number of arguments allowed. - max_arg_length: maximum length (characters) for any single argument. - Violations raise ValueError describing the problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
command
|
str | int | float | Iterable[Any] | None
|
Shell string, int, float, or an iterable of arguments (e.g., list/tuple/generator), or None. |
required |
shlex_split
|
bool
|
Whether to shell-split string input. Ignored for non-strings. |
True
|
max_items
|
int
|
Upper bound on argv length. |
256
|
max_arg_length
|
int
|
Upper bound on each argument length (len in characters). |
4096
|
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: The argv vector. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If command is of an unsupported type. |
ValueError
|
If max_items/max_arg_length are invalid, or limits are exceeded. |
Examples:
>>> clify('git commit -m "Initial commit"')
['git', 'commit', '-m', 'Initial commit']
>>> clify("python -c 'print(1)'", shlex_split=False)
["python -c 'print(1)'"]
>>> clify(['echo', 123, True])
['echo', '123', 'True']
>>> from pathlib import Path
>>> clify(['ls', Path('/tmp')])
['ls', '/tmp']
>>> clify(42)
['42']
>>> clify(3.14)
['3.14']
>>> clify(None)
[]
Source code in c108/cli.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | |