- Core Functionality
- Logging
- Notifications
- Miscellaneous
shrun can be configured by either CLI args or a toml config file. Most arguments exist in both formats -- where they have the same name -- though some exist only as CLI args. The following describes the CLI args. See config.toml for a description of the toml file.
Tip
Some options allow an off value, which disables toml configuration for that field. For example, --console-log-command off will disable command logging, regardless of the toml settings.
Note
shrun colors its logs, and the examples shown here should use these colors. Unfortunately github does not render them, so you will have to view this markdown file somewhere else to see them.
Arg: -c, --config (PATH | off)...
Description: Path(s) to TOML config file(s). This argument can be given multiple times, in which case all keys are merged. When there is a conflict, the right-most config wins. The legends are also merged, with the same right-bias for conflicting keys. The string off disables all config files to its left. Finally, we also search in specific locations automatically. These are:
<XDG_config>/shrun/config.toml./.shrun.toml./shrun.toml
These files are considered 'left' of any configs explicitly given with --config, hence disabed with off.
Examples can be found in examples.
In addition to providing an alternative to CLI args, the config file has a legend section. This allows us to define aliases for commands. Each alias has a key and a value. The value can either be a single unit or a list of units, where a unit is either a command literal (e.g. bash expression) or a recursive reference to another alias.
Example: For instance, given the section
legend = [
{ key = 'cmd1', val = 'echo "command one"' },
{ key = 'cmd2', val = 'cmd1' },
{ key = 'cmd3', val = 'cmd2' },
{ key = 'cmd4', val = 'command four' },
{ key = 'all', val = ['cmd3', 'cmd4', 'echo hi'] },
]Then the command
$ shrun --config=path/to/config all "echo cat"Will run echo "command one", command four, echo hi and echo cat concurrently. A picture is worth a thousand words:
$ shrun --config=examples/config.toml all "echo cat"
[Success][echo cat] 0 seconds
[Success][echo hi] 0 seconds
[Success][cmd1] 0 seconds
[Error][cmd4] 0 seconds: /bin/sh: line 1: four: command not found
[Finished][0|0|1|3] 0 seconds
Caution
Duplicate keys will cause a parse error to be thrown when loading. Cyclic keys are also disallowed, though these will only throw if you actually try to execute one (i.e. merely having cyclic definitions in the legend will not throw an error).
Arg: --edges (EDGES_STR | && | || | ;; | off)
Description: Comma-separated list, specifying command dependencies, based on their order. There are three edge types:
- and:
cmd1 & cmd2, runs cmd2 iff cmd1 succeeds. - or:
cmd1 | cmd2, runs cmd2 iff cmd1 fails. - any:
cmd1 ; cmd2, runs cmd2 iff cmd1 finishes.
The literals are equivalent to placing edges between all commands e.g. && puts an and-edge between all commands.
Example:
# Normally, the 'sleep 1' command would start and finish first$ shrun --init --edges '1 & 3, 2 & 3' "sleep 2" "sleep 2" "sleep 1" "sleep 3" [Success][sleep 2] 2 seconds [Success][sleep 2] 2 seconds [Success][sleep 3] 3 seconds [Success][sleep 1] 1 seconds [Finished][0|0|0|4] 3 seconds
Tip
See the faq for more.
Arg: -i,--init (STRING | off)
Description: If given, init is run before each command. That is, shrun --init "some logic" foo bar is equivalent to shrun "some logic && foo" "some logic && bar".
Example:
$ shrun --init ". examples/bashrc" bash_function
[Success][bash_function] 0 seconds
[Finished][0|0|0|1] 0 seconds
vs.
$ shrun bash_function
[Error][bash_function] 0 seconds: /bin/sh: line 1: bash_function: command not found
[Finished][0|0|1|0] 0 seconds
Arg: --legend-keys-cache (add | clear | write | off)
Description: Shrun allows saving legend keys from the current config file so that we can get tab-completions on the next run.
- add: The default. Combines keys from this run with the prior run(s).
- clear: Deletes the keys file, if it exists.
- write: Saves keys from this run only.
Example:
# config1.toml
legend = [
{ key = 'short', val = 'same as config.toml' },
{ key = 'cfg1_key_1', val = 'val 1' },
{ key = 'cfg1_key_2', val = 'val 1' }
]
# config2.toml
legend = [
{ key = 'short', val = 'same as config.toml' },
{ key = 'cfg2_key_1', val = 'val 2' },
{ key = 'cfg2_key_2', val = 'val 2' }
]$ shrun -c config1.toml --legend-keys-cache add "sleep 1"
[Success][sleep 1] 1 second
[Finished][0|0|0|1] 1 second
$ cat ~/.local/state/shrun/legend-keys.txt
cfg1_key_1
cfg1_key_2
short
$ shrun -c config2.toml --legend-keys-cache add "sleep 1"
[Success][sleep 1] 1 second
[Finished][0|0|0|1] 1 second
$ cat ~/.local/state/shrun/legend-keys.txt
cfg1_key_1
cfg1_key_2
cfg2_key_1
cfg2_key_2
short
$ shrun -c config2.toml --legend-keys-cache write "sleep 1"
[Success][sleep 1] 1 second
[Finished][0|0|0|1] 1 second
$ cat ~/.local/state/shrun/legend-keys.txt
cfg2_key_1
cfg2_key_2
short
$ shrun -c config1.toml --legend-keys-cache off "sleep 1"
[Success][sleep 1] 1 second
[Finished][0|0|0|1] 1 second
$ cat ~/.local/state/shrun/legend-keys.txt
cfg2_key_1
cfg2_key_2
short
$ shrun -c config1.toml --legend-keys-cache clear "sleep 1"
[Success][sleep 1] 1 second
[Finished][0|0|0|1] 1 second
$ cat ~/.local/state/shrun/legend-keys.txt
cat: legend-keys.txt: No such file or directory
Arg: -t, --timeout (NATURAL | STRING | off)
Description: Non-negative integer setting a timeout. Can either be a raw number (interpreted as seconds), or a "time string" e.g. 1d2h3m4s or 2h3s. Defaults to no timeout.
Example:
$ shrun --timeout 4 "sleep 2" "sleep 6" "sleep 8"
[Success][sleep 2] 2 seconds
[Warn] Timed out
[Warn] Attempting to cancel:
- sleep 6
- sleep 8
[Finished][0|2|0|1] 5 seconds
This is general logging config.
Arg: --common-log-debug (on | off)
Description: Enables additional debug logs.
Example:
$ shrun --common-log-debug "sleep 2"
[Debug][sleep 2] Command: 'ShellCommand "sleep 2"'
[Success][sleep 2] 2 seconds
[Finished][0|0|0|1] 2 seconds
Arg: --common-log-key-hide (on | off)
Description: By default, we display the key name from the legend file over the actual command that was run, if the former exists. This flag instead shows the literal command. Commands without keys are unaffected.
Example:
$ shrun --common-log-key-hide --config=examples/config.toml some-key
[Success][echo hi && sleep 2] 2 seconds
[Finished][0|0|0|1] 2 seconds
rather than the usual
$ shrun --config=examples/config.toml some-key
[Success][some-key] 2 seconds
[Finished][0|0|0|1] 2 seconds
Naturally, this does not affect commands that do not have a key (i.e. those not in a legend file). Also, if the commands are defined recursively, then the key name will be the final key.
Configuration for command logs, enabled by console-log.command and/or file-logging.
Arg: --command-log-buffer-length NATURAL
Description: Max text length held by the log buffer, used in conjunction with --command-log-read-strategy block-line-buffer. Defaults to 1,000 characters.
Example:
Note
In this example, the log 'hi' is printed even though it is not newline-terminated, because the --command-log-buffer-length 1 is exceeded (2 characters). On the other hand, the final log 'b' is not printed until the very end since it is within the buffer limit.
$ shrun --command-log-buffer-length 1 "printf hi && sleep 1 && printf b && sleep 2"
[Command][printf hi && sleep 1 && printf b && sleep 1] hi
[Status][0|1|0|0] 1 second
Arg: --command-log-buffer-timeout (NATURAL | STRING)
Description: Max time the log buffer will hold a log before flushing it, used in conjunction with --command-log-read-strategy block-line-buffer. Defaults to 30 seconds.
Example:
Note
In this example, the logs 'hi' and 'b' are printed even though they are not newline-terminated, because the --command-log-buffer-timeout 1 is exceeded (1 second).
$ shrun --command-log-buffer-timeout 1 "printf hi && sleep 3 && printf b && sleep 1"
[Command][printf hi && sleep 3 && printf b && sleep 1] hi
[Status][0|1|0|0] 1 second
$ shrun --command-log-buffer-timeout 1 "printf hi && sleep 3 && printf b && sleep 1"
[Command][printf hi && sleep 3 && printf b && sleep 1] b
[Status][0|1|0|0] 3 seconds
Arg: --command-log-poll-interval NATURAL
Description: Non-negative integer that determines how quickly we poll commands for logs, in microseconds. A value of 0 is interpreted as infinite i.e. limited only by the CPU. Defaults to 10,000.
Warning
Note that lower values will increase CPU usage. In particular, 0 will max out a CPU thread.
Example:
$ shrun --command-log-poll-interval 100 "for i in {1..10}; do echo hi; sleep 1; done"
[Command][for i in {1..10}; do echo hi; sleep 1; done] hi
[Status][0|1|0|0] 7 seconds
Arg: --command-log-read-size BYTES
Description: The max number of bytes in a single read when streaming command logs. Logs larger than --command-log-read-size will be read in a subsequent read, hence broken across lines. The default is 16 kb.
Example:
Note
In this example we also use --command-log-poll-interval 1_000_000 to slow down the reads, so that we can see acbde and f are indeed read separately. Ordinarily this would be too fast to see the difference.
$ shrun --command-log-read-size 5b --command-log-poll-interval 1_000_000 "echo abcdef && sleep 2"
[Command][echo abcdef && sleep 2] abcde
[Status][0|1|0|0] 1 second
$ shrun --command-log-read-size 5b --command-log-poll-interval 1_000_000 "echo abcdef && sleep 2"
[Command][echo abcdef && sleep 2] f
[Status][0|1|0|0] 2 seconds
Arg: --command-log-read-strategy (block | block-line-buffer)
Description: Strategy for reading command logs. block-line-buffer is allowed (and the default) as long as we do not have multiple commands with file logging. In that scenario, we use block.
- block: Reads
N(--command-log-read-size) bytes at a time. - block-line-buffer: Also reads
Nbytes at a time, but buffers newlines, for potentially nicer formatted logs.
Warning
The block-line-buffer strategy only makes sense when there is exactly one command. Otherwise we could easily mix up logs from different commands, leading to nonsense output.
Example:
Note
This is the previous example, but with --command-log-read-strategy block-line-buffer enabled. Notice the entire 'abcdef' is printed, since 'abcd' is read first, buffered, then 'f\n' is read, and the buffer flushed.
$ shrun --command-log-read-size 5b --command-log-poll-interval 1_000_000 --command-log-read-strategy block-line-buffer "echo abcdef && sleep 2"
[Command][echo abcdef && sleep 2] abcdef
[Status][0|1|0|0] 2 seconds
Config related to console logs.
Arg: --console-log-command (on | off)
Description: This flag gives each command a console region in which its logs will be printed, as opposed to swallowing command logs. Only the latest log per region is shown at a given time. Defaults to on.
Note
When commands have complicated output, the logs can interfere with each other (indeed even overwrite themselves). We attempt to mitigate such situations: see Strip Control.
Example:
$ shrun "for i in {1..2}; do echo hi; sleep 1; done"
[Command][for i in {1..2}; do echo hi; sleep 1; done] hi
[Status][0|1|0|0] 1 second
vs.
$ shrun --console-log-command off "for i in {1..2}; do echo hi; sleep 1; done"
[Status][0|1|0|0] 1 second
Note
Both the commands' stdout and stderr are treated the same, logged with the same formatting. This is because many shell programs perform redirection like echo ... >&2 (i.e. redirect stdout to stderr). Not only does this mean we need to take both if we do not want to skip any output, but it also means it does not make sense to try to differentiate the two anymore, as that information has been lost.
Practically speaking, this does not have much effect, just that if a command dies while --console-log-command is enabled, then the final [Error] ... output may not have the most relevant information. See --file-log for details on investigating command failure.
Arg: --console-log-command-name-trunc (NATURAL | off)
Description: Non-negative integer that limits the length of commands/key-names in the console logs. Defaults to no truncation.
Example:
$ shrun --console-log-command-name-trunc 10 "for i in {1..3}; do echo hi; sleep 1; done"
[Success][for i i...] 3 seconds
[Finished][0|0|0|1] 3 seconds
Arg: --console-log-line-trunc (NATURAL | detect | off)
Description: Non-negative integer that limits the length of console logs. Can also be the string literal detect, to detect the terminal size automatically. Defaults to detect if --console-log-command is on.
Note
"log prefixes" (e.g. labels like [Success], timestamps) are counted towards total length, but are never truncated.
Example:
$ shrun --console-log-line-trunc 80 "echo 'some ridiculously long command i mean is this really necessary' && sleep 2"
[Command][echo 'some ridiculously long command i mean is this really necessary' && sleep 2] ...
[Status][0|1|0|0] 1 second
Arg: --console-log-strip-control (all | smart | off)
Description: Control characters can wreak layout havoc, hence this option for stripping such characters.
- all: Strips all such chars.
- smart: The default. Attempts to strip only the control chars that affect layout (e.g. cursor movements) and leaves others unaffected (e.g. colors). This has the potential to be the 'prettiest' though it is possible to miss some chars.
Example:
Note: In the following examples, \033[35m and \033[3D are ansi escape codes. The former sets the text color to magenta, and the latter resets the cursor to the left by 3 places i.e. partially overwrites the previous characters. We also include the options --console-log-command --console-log-command-name-trunc 10 (show command logs and truncate command name to 10 chars) to make the output easier to read.
all strips all control characters: \033 in this case. The means all special formatting / control will be omitted.
$ shrun --console-log-command-name-trunc 10 --console-log-strip-control all "echo -e ' foo \033[35m hello \033[3D bye '; sleep 2"
[Command][echo -e...] foo hello bye
[Status][0|1|0|0] 1 second
off leaves all control characters in place. In this case, we will apply both the text coloring (\033[35m) and text overwriting (\033[3D).
$ shrun --console-log-command-name-trunc 10 --console-log-strip-control off "echo -e ' foo \033[35m hello \033[3D bye '; sleep 2"
[Command][echo -e...] foo hel bye
[Status][0|1|0|0] 1 second
smart removes the control chars but leaves the text coloring, so we will have the magenta text but not overwriting.
$ shrun --console-log-command-name-trunc 10 --console-log-strip-control smart "echo -e ' foo \033[35m hello \033[3D bye '; sleep 2"
[Command][echo -e...] foo hello bye
[Status][0|1|0|0] 1 second
Arg: --console-log-timer-format TIME_FMT
Description: How to format the timer. Options:
- digital_compact: e.g.
02:00:03. - digital_full: e.g.
00:02:00:03. - prose_compact: The default e.g.
2 hours, 3 seconds. - prose_full: e.g.
0 days, 2 hours, 0 minutes, 3 seconds.
Example:
$ shrun --console-log-timer-format digital_compact "sleep 2"
[Status][0|1|0|0] 01
$ shrun --console-log-timer-format digital_full "sleep 2"
[Status][0|1|0|0] 00:00:00:01
$ shrun --console-log-timer-format prose_compact "sleep 2"
[Status][0|1|0|0] 1 second
$ shrun --console-log-timer-format prose_full "sleep 2"
[Status][0|1|0|0] 0 days, 0 hours, 0 minutes, 1 second
Config related to file logs.
Arg: -f, --file-log (default | PATH | off)
Description: If a path is supplied, all logs will additionally be written to the supplied file. Furthermore, command logs will be written to the file irrespective of --console-log-command. Console logging is unaffected. This can be useful for investigating command failures. If the string default is given, then we write to the XDG state directory e.g. ~/.local/state/shrun/shrun.log.
Example:
$ shrun --file-log=out.log "sleep 2" "bad" "for i in {1..3}; do echo hi; sleep 1; done"
[Error][bad] 0 seconds: /bin/sh: line 1: bad: command not found
[Success][sleep 2] 2 seconds
[Success][for i in {1..3}; do echo hi; sleep 1; done] 3 seconds
[Finished][0|0|1|2] 3 seconds
$ cat out.log
[2022-12-12 23:17:55][Command][for i in {1..3}; do echo hi; sleep 1; done] hi
[2022-12-12 23:17:55][Command][bad] /bin/sh: line 1: bad: command not found
[2022-12-12 23:17:55][Error][bad] 0 seconds: /bin/sh: line 1: bad: command not found
[2022-12-12 23:17:56][Command][for i in {1..3}; do echo hi; sleep 1; done] hi
[2022-12-12 23:17:57][Success][sleep 2] 2 seconds
[2022-12-12 23:17:57][Command][for i in {1..3}; do echo hi; sleep 1; done] hi
[2022-12-12 23:17:58][Success][for i in {1..3}; do echo hi; sleep 1; done] 3 seconds
[2022-12-12 23:17:58][Finished][0|0|1|2] 3 seconds
Arg: --file-log-command-name-trunc (NATURAL | off)
Description: Like --console-log-command-name-trunc, but for --file-logs.
Example:
$ shrun --file-log out.log --file-log-command-name-trunc 10 "for i in {1..3}; do echo hi; sleep 1; done"
[Success][for i in {1..3}; do echo hi; sleep 1; done] 3 seconds
[Finished][0|0|0|1] 3 seconds
$ cat out.log
[2024-04-23 01:05:21][Command][for i i...] Starting...
[2024-04-23 01:05:21][Command][for i i...] hi
[2024-04-23 01:05:22][Command][for i i...] hi
[2024-04-23 01:05:23][Command][for i i...] hi
[2024-04-23 01:05:24][Success][for i i...] 3 seconds
[2024-04-23 01:05:24][Finished][0|0|0|1] 3 seconds
Arg: --file-log-delete-on-success (on | off)
Description: If --file-log is active, deletes the file on a successful exit. Does not delete the file if shrun exited via failure.
Example:
$ shrun --file-log del-on-success.log --file-log-delete-on-success on "sleep 2"
[Success][sleep 2] 2 seconds
[Finished][0|0|0|1] 2 seconds
$ cat del-on-success.log
cat: del-on-success.log: No such file or directory
vs.
$ shrun --file-log del-on-success.log --file-log-delete-on-success on bad "sleep 2"
[Error][bad] 0 seconds: /bin/sh: line 1: bad: command not found
[Success][sleep 2] 2 seconds
[Finished][0|0|1|1] 2 seconds
$ cat del-on-success.log
[2024-04-23 01:05:21][Command][bad] Starting...
[2024-04-23 01:05:21][Command][sleep 2] Starting...
[2024-04-23 01:05:21][Error][bad] 0 seconds: /bin/sh: line 1: bad: command not found
[2024-04-23 01:05:24][Success][sleep 2] 2 seconds
[2024-04-23 01:05:24][Finished][0|0|1|1] 2 seconds
Tip
This option allows for a nice workflow with automatic file logging i.e. setting the config:
[file-log]
path = "shrun.log"
delete-on-success = "on"If the command succeeds we do not leave any log files around, but if it fails, we have an easy way to investigate.
Arg: --file-log-line-trunc (NATURAL | detect | off)
Description: Like --console-log-line-trunc, but for file logs. Defaults to off.
Example:
$ shrun --file-log line-trunc.log --file-log-line-trunc 120 "echo 'some ridiculously long command i mean is this really necessary' && sleep 2"
[Success][sleep 2] 2 seconds
[Finished][0|0|0|1] 2 seconds
$ cat line-trunc.log
[2024-04-23 01:05:21][Command][echo 'some ridiculously long command i mean is this really necessary' && sleep 2] Star...
[2024-04-23 01:05:22][Command][echo 'some ridiculously long command i mean is this really necessary' && sleep 2] som...
[2024-04-23 01:05:24][Success][echo 'some ridiculously long command i mean is this really necessary' && sleep 2] 2 se...
[2024-04-23 01:05:24][Finished][0|0|0|1] 2 seconds
Arg: --file-log-mode (append | rename | write)
Description: Mode in which to open the log file. Can be write (the default), append, or rename. The rename option will rename the requested log file if there is a collision e.g. -f shrun.log will become shrun (1).log.
Arg: --file-log-size-mode (delete BYTES | warn BYTES | off)
Description: Sets a threshold for the file log size, upon which we either print a warning or delete the file, if it is exceeded. The BYTES should include the value and units e.g. warn 10 mb, warn 5 gigabytes, delete 20.5B. Defaults to warning at 50 mb.
Exmaple:
$ shrun --file-log size_mode_warn.log --file-log-size-mode "warn 1 b" "sleep 2"
Warning: log file 'size_mode_warn.log' has size: 11.00 b, but specified threshold is: 1.00 b.
[Success][sleep 2] 2 seconds
[Finished][0|0|0|1] 2 seconds
$ shrun --file-log size_mode_warn.log --file-log-size-mode off "sleep 2"
[Success][sleep 2] 2 seconds
[Finished][0|0|0|1] 2 seconds
Arg: --file-log-strip-control (all | smart | off)
Description: --console-log-strip-control for file logs created with --file-log. Defaults to all.
These options configure shrun to send off desktop notifications for certain actions i.e. a command finishes or shrun itself finishes.
Arg: --notify-action-complete (all | command | final | off)
Description: Sends notifications for 'complete' actions.
- all: Implies
finalandcommand. - command: Sends off a notification for each command that finishes.
- final: Sends off a single notification when shrun itself finishes.
Example:
$ shrun --notify-system dbus --notify-action-complete final "sleep 5"
Arg: --notify-action-start (on | off)
Description: Sends notifications for 'start' actions.
Example:
$ shrun --notify-system dbus --notify-action-start on "sleep 5"
Arg: --notify-system (dbus | notify-send | apple-script)
Description: The system used for sending notifications. dbus and notify-send are available on linux, whereas apple-script is available for osx.
Example:
$ shrun --notify-system dbus "sleep 5"
Arg: --notify-timeout (NATURAL | off)
Description: When to timeout success notifications. Defaults to 10 seconds.
Example:
$ shrun --notify-system dbus --notify-timeout off "sleep 5"
Note
Timeouts are subject to the whims of the underlying notification system e.g. some notification systems ignore the timeout entirely. Also, "error notifications" (i.e. shrun or command failures) are sent with urgency = critical where supported, thus may not timeout at all, per FDO's specification.
Arg: --default-config
Description: Writes a default configuration to stdout.
Arg: --dry-run
Description: Prints the configuration and commands that would be run to stdout, then exits.