9

NOTE I edited the question, since the use of PG_HOST was causing confussion, but the spirit is the same

I am running a shiny app that needs read some environment variables.

That variables are defined before the shiny server starts. For example

export APPLE=apple
export PENCIL=pencil

In the global.R (or at the beggining of server.R is the same) I wrote the following code:

manzana <- Sys.getenv('APPLE')
lapiz <- Sys.getenv('PENCIL')

but those variables are empty.

If I run that code in the R console, both returns the correct value.

Whay this is not working? Whay is different the R console and the shiny app? How I can get the real environment variables (in this fake example $APPLE and $PENCIL)? Which is the correct way of configuring the shiny app?

nanounanue
  • 7,942
  • 7
  • 41
  • 73
  • The PATH in your shell is different than the PATH seen by R. Try `system("echo $PG_HOST")` at the R console to see that this is true. Since you know how to use `Sys.getenv`, the way forward should be clear now. – IRTFM Apr 26 '16 at 02:12
  • 2
    Thank you for you answer, and effectively, `Sys.getenv` returns very differently in the console and in the shiny app. I am not an expert (obviously), but I don't know how to follow from here. Could you be more specific, please? – nanounanue Apr 26 '16 at 03:21
  • couple of important questions....is the database a cloud db or is it flat file? Does it require auth? When you deploy a shiny app...the path to your local file system will be invalid...because it's not served from your local machine. There are workarounds...ie update your db locally and then push new db to a cloud file that is called from your app. – Carl Boneri Apr 26 '16 at 03:31
  • You should really just read this http://www.postgresql.org/docs/8.3/static/libpq-envars.html – Carl Boneri Apr 26 '16 at 03:32
  • 2
    @CarlBoneri thank you for your answer, but the problem is that shiny is not reading the environment variables as expected. Any environment variable. – nanounanue Apr 26 '16 at 04:06
  • If you wanted to change the value of PATH that you were getting from `Sys,getenv` then I thought that using `Sys.setenv` was the obvious next step. If you were going to make the new location first on the search path then it would be something along the lines of `Sys.setenv( PATH=paste( "", Sys.getenv("PATH"), sep=":") )`. Cannot give much in the way of tested code since you have offered virtually no specifics. – IRTFM Apr 26 '16 at 04:18
  • @42- I edited the question. I cannot use the value in the terminal for editing the code in the shiny app, I want to dinamically read the environment variables. – nanounanue Apr 26 '16 at 04:35
  • I have a similar problem, did you find a solution. I want to read environment variables because they are used to store the connection strings to a database. – Paul Rougieux Apr 27 '18 at 12:16

2 Answers2

0

For those who, like me, are finding this question years later, the secret of getting this to work depends on two things:

  • Setting the environment variable permanently
  • Making it available to the user shiny on the server computer

So, for example, the app:

library(shiny)

ui <- fluidPage(
  h1(paste("Run by", Sys.getenv("USER"))),
  textInput("name", "What is your name?", value = "Friendly User"),
  actionButton("greet", "Greet"),
  textOutput("greeting")
)


server <- function(input, output, session) {
  output$greeting <- renderText({
    req(input$greet)
    paste0(Sys.getenv("greeting"), " ", isolate(input$name), "!")
  })
}

shinyApp(ui, server)

Run after the command export greeting='Hello' should say "Hello Friendly User!" if it's finding the correct environment variable, but:

enter image description here

The export statement only sets the environment variable for that session (when you have the terminal open). Even with shiny as user, the session you set the variable in will differ from the session the server is running (which, I think, is constant whilst the server is up). However, see that Sys.getenv("USER") is correctly discovering the system environment variable specifying that the user running the server is shiny.

There are a number of ways of setting environment variables for a shiny server, most of which would require the restarting of the server after running the command (not always possible). If you set it in /etc/environment then it should allow all users (including shiny) to access it whenever it's requested without requiring a restart:

echo greeting='Hello' >> /etc/environment

gives:

enter image description here

For further details, and to try out various options, here's a docker image of the above app, created from this Dockerfile which runs the setting environment variable command.

Andy Baxter
  • 5,833
  • 1
  • 8
  • 22
-1

First step is to understand reactivity. Check out the shiny tutorials.

using your example..kind of..heres an app the updates and sets variables that can be called numerous ways....

shiny_example <- function(){

  server <- shinyServer(function(session,input,output){
    the_slots <- list(Apple = 'apple',Green = 'green')

    make_globs <- function(new_var = NULL){
      if(!is.null(new_var)){
        the_slots <<- append(the_slots,new_var)
      }
    }

    glob_vals <- the_slots

    glob_vals <- eventReactive(input$saver, {
      set_new_vars <- list(input$new_var)
      names(set_new_vars) <- input$new_var_name
      the_slots <<- make_globs(new_var = set_new_vars)
      lapply(list('new_var','new_var_name'),function(i)updateTextInput(session,i, value = ""))
      return(the_slots)

    })

    output$envs <- renderPrint({

      glob_vals()

    })

    output$sels <- renderUI({
      vals <- 1:length(glob_vals())
      Opts <- unlist(lapply(vals,function(i)sprintf('<option value="%s">%s</option>',i,names(glob_vals()[i])))) %>% HTML
      HTML(
        paste(
          "<div class='shiny-input-container'>",
          "<label class='control-label' for='the_ups'></label>",
          "<div><select id='the_ups'>",Opts,"</select></div>",
          "</div>",sep=""))
    })

    output$sel_vals <- renderPrint({
      ref_cards <- lapply(1:length(glob_vals()),function(i)
        data.frame(the_names = names(glob_vals()[i]),the_vals = glob_vals()[[i]]))%>%
        rbind.pages

      ref_cards[input$the_ups,'the_vals']


    })

  })


  ui <- shinyUI(
    bootstrapPage(
      tags$div(class="container",
               fluidRow(
                 tags$h4(HTML('These inputs will update the variable list \n like a variable in Sys.getenv()')),
                 column(6,textInput(inputId = "new_var_name",label = "variable name")),
                 column(6,textInput(inputId = "new_var",label = 'variable value'))
               ),
               fluidRow(

                 column(6,
                        tags$h4(
                          HTML('Pressing the `add_new` button will load the variables and display the corresponding values below'),
                          actionButton(inputId = "saver",label = "add_new")
                        )),
                 column(6,tags$h4("You can even dynamically update a selection input with newly created paths or environment variables"),
                        uiOutput('sels'))
               ),
               fluidRow(
                 column(6,verbatimTextOutput('envs')),
                 column(6,verbatimTextOutput('sel_vals')))
      )))

  shinyApp(ui,server)

}

And the result: enter image description here

Carl Boneri
  • 2,632
  • 1
  • 13
  • 15
  • 2
    Thank you again, but I really want to read a variable from the environment with `Sys.getenv` ... – nanounanue Apr 26 '16 at 06:23
  • Can I ask why? Sys.getenv is a function that plucks a named variable from a stored list... But anyways, best of luck – Carl Boneri Apr 26 '16 at 06:41
  • 3
    I don't want to hardcode some information (like passwords, urls, ports etc.) So i though that I could read it from the environment variables. That's what Sys.getenv does – nanounanue Apr 26 '16 at 06:50