The exec
engine allows to execute an arbitrary command on the code chunk
content, optionally with arguments. If any, they are passed to engine.opts
and
they could be one of the following:
engine.opts = list(command, input, ext, clean, args, args1, args2, output)
The execution of the chunk will be equivalent to this command line
<command> <args1> <args> <args2>
Behavior by default, during evaluation will be:
command
option.f
clean
function to execute on exit, basically to remove the
temp file f
.args1()
, with args()
then args2()
.There should be very rare usage of changing the default behavior, but it can be useful to debug for example or other advanced usage.
You can find some examples below on how to use each option. We are using
Rscript
an d python
only in the examples below by convenience but this works
with any executables.
command
can be the name of a command in PATH.
```{exec, command='Rscript'} 1 + 1
```{exec, command='python'} print(1 + 1)
or a full path
```{exec, command = Sys.which('python'), message = FALSE} print("Full path command works")
It can also be passed as an option in `engine.opts`. ```{exec, engine.opts = list(command ='python')} print(1 + 1)
It is the only option that can be passed as the top-level chunk option.
All other options should be provided in the chunk option engine.opts
in a
list. (As you have seen above, command
can be optionally in engine.opts
,
too).
They can take character values or functions that returns character values.
It returns the temporary file path that will be used as the input of the command.
It is a function of two argument function(code, file){}
- By default, function
is writing code
into the temporary file that will be executed by the command.
This can be changed if needed for other side-effects. You would still want to
write the code
into a file (using xfun::write_utf8()
or another function)
otherwise the command will be executed with an empty file.
input2 <- function(code, file) { xfun::write_utf8("print('file2 executed')", file) file }
```{exec, engine.opts=list(command = 'python', input = input2)} print(1 + 1)
You can also pass a string directly to input to change the name of the input file that will be passed to the command ```{exec, command='python', engine.opts=list(input = "myfile.py")} print(1 + 1)
This can be useful for debugging. See more about this usage in the clean
option part below.
This will determine the extension to use with the temporary file. By default, the extension will be the name of the command file. Use this option to change it.
For example, this will ensure the tempfile has a .R
extension.
```{exec, engine.opts = list(command='Rscript', ext = 'R')} 1 + 1
It can be a function of the executable name (i.e `basename(command)`). ```r ext_fun <- function(name) { if (grepl("Rscript", name)) return("R") if (grepl("python", name)) return("py") name }
```{exec, command = 'python', engine.opts = list(ext = ext_fun)} print(1 + 1)
The extension of the temporary does not really matter most of the time but you can use this option if the command you use needs it. ## args, args1, args2 <command> <args1()> <args(code, f)> <args2()> - `args1` will be the first argument(s) to be passed after the command line. - `args` will the main argument passing the temporary input file path to the command. - `args2` will be the last argument(s) to be passed, after the file argument. `args` will be by default the temporary file path. If customized, it can be a function of 2 arguments `function(code, file)`. In this example, a line is preprended in the file before being run. ```r f_arg <- function(code, file) { # prepend a command xfun::append_utf8("print('# file modified in args')", file, sort = rev) file }
```{exec, engine.opts=list(command = 'python', args = f_arg)} print(1 + 1)
It can be combined with args1 to pass an argument before in the command line. For example, here passing `-x` to `python`, which will ignore the prepended line: ```{exec, engine.opts=list(command = 'python', args1 = '-x', args = f_arg)} print(1 + 1)
With setting args
to a string, you could easily use the exec
engine to
execute a string.
We are writing this content to custom.py
```{cat, engine.opts = list(file = 'custom.py', lang = 'python')} print("Hello from a python file!")
That we can execute using an empty `exec` engine chunk ```{exec, command = 'python', engine.opts=list(args = 'custom.py'), echo = FALSE}
# clean the demo file unlink('custom.py')
args2
will be passed after. It could be useful if your code contains
arguments, for example:
```{exec, command = 'python', engine.opts=list(args2 = 'hello')} import sys print('And the argument is: '+sys.argv[1])
## clean By default, the temporary file will be removed. This option can be set to `NULL` to keep this file for example to debug. ```{exec, command = 'python', engine.opts = list(clean = NULL)} print('This content can be read if you open the file left')
A file with extension .python
should be still here
f1 <- list.files('.', pattern = "python.*\\.python") file.exists(f1)
if (length(f1) == 1) unlink(f1)
It can be useful in addition to setting input
option so that you can easily
retrieve the file to re-run at command line yourself.
``{exec, command='python', engine.opts = list(input='tmp-debug.py', clean=NULL)}
print('This content can be rerun using
temp-debug.py` file')
You can find the `tmp-debug.py` file in your working directory and which can help debug using command line by running `python tmp-debug.py` for example. ```r unlink('tmp-debug.py')
The output
option can take a function of arguments options
, code
,
output
, and file
. The function should return a character string as the final
output of the engine. By default, this function calls knitr::engine_output()
.
See the last section for an example of creating a gcc
engine based on the
exec
engine.
Will output nothing
```{exec, command = 'python', eval = FALSE} print(1 + 1)
## Error is caught ```{exec, command = 'Rscript', error = TRUE} print(1 + "")
exec
Below is an example of calling gcc
to generate an executable, and run the
executable.
Register the new gcc
engine:
knitr::knit_engines$set(gcc = function(options) { # set the command to gcc options$command = 'gcc' opts = list( # set file extension to .c ext = 'c', # gcc input -o output args = function(code, file) { c(file, '-o', xfun::sans_ext(file)) }, # run the executable and capture stdout output = function(options, code, output, file) { out = system2(paste0('./', xfun::sans_ext(file)), stdout = TRUE) knitr::engine_output(options, code, out) }, # delete the temp .c file and the executable clean = function(file) { file.remove(c(file, xfun::sans_ext(file))) } ) options$engine.opts = knitr:::merge_list(opts, options$engine.opts) # pass options to the exec engine to compile and run the C code eng_exec = knitr::knit_engines$get('exec') eng_exec(options) })
A hello world example:
#include <stdio.h> int main() { printf("Hello world!"); return 0; }
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.