Using Commands from Pluto

Is it possible to use external operating system commands from Pluto to automate the fossil add harold/tiddlers/* step, so that only the final commit has to be done manually from the console?

Hi! Yes, you can run shell[1] commands from within Julia and hence Pluto notebooks, e.g. you can run the “list directory” command ls on Unix-like systems by running a cell containing this code:

run(`ls`)

This creates a “command object” of type Cmd and then runs this command with the function run. You can check the documentation of run and Cmd for a lot more details on how to run this.

Beware that all cells will be run at every startup of a Pluto notebook and all cells that depend on changed cells will also be re-run upon changes. With external shell commands this may or may not be what you want, but there are also ways to avoid running the “command cell” every time you change some dependency of it.

PS: The run will return the result of the process, so it will usually print the output or show some error codes if the command failed.


  1. The commands are not run in a shell, actually, see my reply below. ↩︎

Thanks a lot for your help.
I’m going to give it a try and let you know if it works. I really appreciate it.

You’re very welcome. And I just realized that I forgot to mention that the command object constructed by Julia might need to be created a bit carefully when it contains special characters (like the * in your example). Julia actually doesn’t run the commands in any shell, but executes them directly. So the * probably doesn’t do what you would like it to.

E.g. if the command you want to run is

cmd = `fossil add harold/tiddlers/*`
run(cmd)

Julia first complains about the unquoted * (so you would need to write \*) but then also won’t do what you want, because the expansion of * to all the files in the directory is a feature of Bash (or other shells), called “globbing”. This is not done by run though, see e.g. here Quoting in shell commands and the related discussions, e.g. here Removing directory contents recursively.

Probably the easiest way around it is to explicitly run the command in a shell, e.g. with bash -c '...'

cmd = `bash -c 'fossil add harold/tiddlers/*'`
run(cmd)

This should then have the complete expected behavior of the shell you’re running it in (if it’s Bash). The downside is that you rely on Bash being installed on the system, but if not, it can be easily adapted.