yihui / knitr

A general-purpose tool for dynamic report generation in R
https://yihui.org/knitr/
2.39k stars 878 forks source link

Problem trying to source ~/.bashrc in bash chunk #1762

Open ftabaro opened 5 years ago

ftabaro commented 5 years ago

I am trying to use some aliases within a bash chunk in my R notebook. These aliases are defined in my ~/.bashrc or ~/.bash_profile file. Using the standard {bash} engine it throws an error. It means that ~/.bashrc or ~/.bash_profile is not sourced at bash startup. I have then written an hook to force the sourcing in my setup chunk as follow:

knitr::knit_hooks$set(engine.opts = function (options) {
  options$engine.opts <- list(bash="--init-file ~/.bash_profile -i")
  return(options)
})

I tested the resulting bash invocation in bash terminal: bash --init-file ~/.bash_profile -i -c "alias ll" and generates the expected output. I have then inspected the source code for the engine function and I suspect there is a typo messing with engine.opts setting.

In my opinion the hook is not necessary, because the bash invocation sources the ~/.bashrc or ~/.bash_profile automatically. Is it that rstudio/knitr runs the bash chunk as different user? I tried to run whoami inside a chunk and my username is returned. So, why the ~/.bashrc or ~/.bash_profile file is not sourced?

EDIT: setting knitr::opts_chunk$set(engine.opts = list(bash="--init-file ~/.bash_profile -i")) in setup chunks does not work either.

yihui commented 5 years ago

I'm surprised that ~/.bash_profile is not automatically sourced. I don't have time to investigate this issue, but if you can figure out the problem and submit a pull request to fix it, I may be able to review it. Thank you!

cderv commented 4 years ago

I think this is because startup script are not loaded the same way when bash is use non-interactively. This page describe the behavior. https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html

For this information, several solutions I tested

echo $BASH_LOADED
* Modify you startup script to define `BASH_LOADED` environment variable in each tests.
* Run with `knitr::knit('test.Rmd')`

Here are the results I got:

* Setting BASH_ENV seems to work 
```r
Sys.setenv(BASH_ENV="~/.bashrc")
knitr::knit("test.rmd")

However, if you already have this env var set, it needs to be taken care of by appending I guess.

If you pass the --login option, it will be as if invoked as an interactive login shell and load the different scripts. Try this

```{bash, engine.opts="--login"}
<your code>
or in a setup chunk
```r
knitr::opts_chunk$set(engine.opts = list(bash="--login"))

it seems to work the same with .bash_profile when I tried.

Also, using -i for interactive shell, works for me loading .bashrc as explain in the doc linked above.

knitr::opts_chunk$set(engine.opts = list(bash="-i"))

and

knitr::opts_chunk$set(engine.opts = list(bash="--init-file ~/.bash_profile -i"))

also work for me.

I tested on centos 7.4.

Does any of the above works for you ? Do you have an error message from bash ?

I'll continue my test with an alias, and not an environment variable.

For reference, there is a similar question in the community https://community.rstudio.com/t/r-markdown-bash-chunk-cannot-source-bashrc/46508

cderv commented 3 years ago

I think at the end, this is maybe a matter of documentation about how the bash engine is working. The startup script is close to a "hell" situation depending on your OS and what you are using (see https://blog.flowblok.id.au/2013-02/shell-startup-scripts.html)

I am not sure knitr could improve this. We plan to add a generic engine to run any command easily for an engine. This could be a way to solve this kind of issue by writing your self the command the engine should use mor explicitly than passing options.

I'll leave that open as a "better doc" needed about the different engines maybe including this one.