Tools for running code in a text file
  • Nix 61.2%
  • Shell 38.8%
Find a file
2023-08-19 19:17:07 +01:00
.gitignore initial commit 2023-06-21 17:11:06 +01:00
flake.lock initial commit 2023-06-21 17:11:06 +01:00
flake.nix initial commit 2023-06-21 17:54:06 +01:00
LICENSE Initial commit 2023-06-21 15:40:50 +00:00
README.md expanded 2023-08-19 19:17:07 +01:00
run-code-inline initial commit 2023-06-21 17:01:48 +01:00

run-code-inline

WARNING: This script attempts to execute any code supplied to it. Only use with code that you know to be trustworthy.

Reads text (e.g., Markdown or Asciidoc) from stdin, echos it to stdout, simultaneously running any commands and inserting the output immediately after the command. This is useful for writing tutorials and software documentation. Any line that begins with $ is assumed to be a command. The commands can launch subshells, subsubshells, and so on... the result should be the same as if you typed the commands at a terminal.

For example, the following input

The "echo" command writes a message to the screen.
Here is an example of how to use it.

~~~
$ echo "Hello, world!"
$ echo "This is fun, isn't it?"
~~~

would result in the output below. Note that the echo commands have been executed and the result included in the output.

The "echo" command writes a message to the screen.
Here is an example of how to use it.

~~~
$ echo "Hello, world!"
Hello, world!
$ echo "This is fun, isn't it?"
This is fun, isn't it?
~~~

If you want to run a command without echoing it to the output, preceed it with $# instead of $. If the command generates messages that you don't want to include in the output, redirect stdin (and perhaps stderr) to /dev/null. However, typically you will use this script to pre-process files before sending them to a publishing tool such as pandoc or asciidoctor. In that scenario, you can simply place the commands inside comments (using the appropriate syntax for the publishing tool). Your command and any output will be included in the pre-processed file (which may be useful for debugging), but not in the final output.

By default, bash is used to process commands. If you want to use a different shell, invoke it as your first command.

One way to invoke this script is

run-code-inline < INFILE > OUTFILE 2>&1

However, you may have intentionally included commands that fail, perhaps to discuss the error messages. In that case, you probably want the error messages to go to stdout rather than stderr, as shown in the example below.

run-code-inline < INFILE > OUTFILE 2>&1

Known issue: exit

The exit command will terminate the entire script. This is a problem if, for example, you want to launch a subshell, perform some actions, and then exit to the main shell.

Known issue: nix-shell

The nix-shell command doesn't work as expected when used with this script; subsequent commands are executed outside the nix shell, typically leading to errors. For example, the code

$ nix-shell -p cowsay
$ cowsay "moo"

will produce the output below.

$ nix-shell -p cowsay
$ cowsay "moo"
bash: line 4: cowsay: command not found

Before I present a full workaround, note that we can use the --run bash switch.

$ nix-shell -p cowsay --run bash << EOL
$ cowsay "moo"
$ EOL

This produces the output below.

$ nix-shell -p cowsay --run bash << EOL
$ cowsay "moo"
 _____
< moo >
 -----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ EOL

For a complete solution, we can hide the workaround using the $# syntax.

$# echo '$ nix-shell -p cowsay'
$# nix-shell -p cowsay --run bash << EOL
$ cowsay "moo"
$# EOL

This produces the output below.

$ nix-shell -p cowsay
$ cowsay "moo"
 _____
< moo >
 -----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Known issue: Nix commands generating weird characters.

Some Nix commands will generate the byte sequence 0d 1b 5b 4d. My workaround is to pipe the output through sed 's/\x0d\x1b.\x4b//g'.