Rscript and user prompts - r

Have a fully working R-script. When executing it from Rscript it doesn't stop to accept user input however.
The user input is some readline statements. The cat statements prompting for input works as intended. Have I missed something?
I execute 'Rscript scriptfile.R' from terminal on macOS.

You can create a function typeline() to read an input line and then use the result for your next commands. It will wait for your input text either you run your code in Rstudio or in terminal:
typeline <- function(msg="Enter text: ") {
if (interactive() ) {
txt <- readline(msg)
} else {
cat(msg);
txt <- readLines("stdin",n=1);
}
return(txt)
}
txt=typeline("your message: ")
print(txt)

Managed to get it to work by changing readline to readLines as mentioned in the post suggested by meenaparam. The downside with this method is that ithe script only works in batch mode, running it in Rstudio makes it hang. Would be good to know a general way to capture keyboard input i.e that works both in interactive and batch mode.

Use this
cat("What's your name? ")
name <- readLines(file("stdin"),1)
cat("What's your age? ")
age <- readLines(file("stdin"),1)
print(name)
print(age)

Related

How to get a user input in command prompt and pass it to R

I am trying to use
var <- as.numeric(readline(prompt="Enter a number: "))
and later use this in a calculation.
It works fine when running in RStudio but I need to be able to pass this input from the command line in Windows 10
I am using a batch file with a single line
Rscript.exe "C:\My Files\R_scripts\my_script.R"
When it gets to the user input part it freezes and it doesn't provide expected output.
From the documentation of readline():
This can only be used in an interactive session. [...] In non-interactive use the result is as if the response was RETURN and the value is "".
For non-interactive use - when calling R from the command line - I think you've got two options:
Use readLines(con = "stdin", n = 1) to read user input from the terminal.
Use commandArgs(trailingOnly = TRUE) to supply the input as an argument from the command line when calling the script instead.
Under is more information.
1. Using readLines()
readLines() looks very similar to readline() which you're using, but is meant to read files line by line. If we instead of a file points it to the standard input (con = "stdin") it will read user input from the terminal. We set n = 1 so that it stops reading from the command line when you press Enter (that is, it only read one line).
Example
Use readLines() in a R-script:
# some-r-file.R
# This is our prompt, since readLines doesn't provide one
cat("Please write something: ")
args <- readLines(con = "stdin", n = 1)
writeLines(args[[1]], "output.txt")
Call the script:
Rscript.exe "some-r-file.R"
It will now ask you for your input. Here is a screen capture from PowerShell, where I supplied "Any text!".
Then the output.txt will contain:
Any text!
2. UsingcommandArgs()
When calling an Rscript.exe from the terminal, you can add extra arguments. With commandArgs() you can capture these arguments and use them in your code.
Example:
Use commandArgs() in a R-script:
# some-r-file.R
args <- commandArgs(trailingOnly = TRUE)
writeLines(args[[1]], "output.txt")
Call the script:
Rscript.exe "some-r-file.R" "Any text!"
Then the output.txt will contain:
Any text!

readline inserts a line break before the prompt in the R console

How can I get a user keyboard input on the current line of the R console?
I have prior output from cat and now want a readline(prompt="") in the same line.
I.e. there should be no line break before the prompt.
I have tried cat("Dummy") ; readline("\r Type sth: ") to no avail.
I cannot include "Dummy" in the prompt call as this is supposed to be a two step process (Some info in the console, prompt user input, more info in the same line, prompt second user input).
Edit: I came up with something that technically works but is not elegant:
{
cat("\014") # clear the entire console
p1 <- readline("prompt1: ")
cat("\014") # clear again, then repeat previous text
p2 <- readline(paste0("promt1: ", p1, ". prompt2: "))
}
A variant without clearing the console is still wanted.

Why does Rstudio print an extra line when printing text with cat?

Consider this code:
{
cat("hello")
Sys.sleep(1)
cat("\rhi there!")
}
In both the terminal and Rstudio we see the word 'hello' followed by 'hi there!' one second later but the terminal ends with hi there!> while Rstudio ends on a new line with >. Is there any way to get both systems to agree on how they print things using some option? Or is this something special that Rstudio does?
Try with
{
cat("hello")
Sys.sleep(1)
cat("\rhi there!\n")
}

Running R script_Readline and Scan does not pause for user input

I have looked at other posts that appeared similar to this question but they have not helped me. This may be just my ignorance of R. Thus I decided to sign up and make my first post on stack-overflow.
I am running an R-script and would like the user to decide either to use one of the two following loops. The code to decide user input looks similar to the one below:
#Define the function
method.choice<-function() {
Method.to.use<-readline("Please enter 'New' for new method and'Old' for old method: ")
while(Method.to.use!="New" && Method.to.use!="Old"){ #Make sure selection is one of two inputs
cat("You have not entered a valid input, try again", "\n")
Method.to.use<-readline("Please enter 'New' for new method and 'Old' for old method: ")
cat("You have selected", Method.to.use, "\n")
}
return(Method.to.use)
}
#Run the function
method.choice()
Then below this I have the two possible choices:
if(Method.to.use=="New") {
for(i in 1:nrow(linelist)){...}
}
if(Method.to.use=="Old"){
for(i in 1:nrow(linelist)){...}
}
My issue is, and what I have read from other posts, is that whether I use "readline", "scan" or "ask", R does not wait for my input. Instead R will use the following lines as the input.
The only way I found that R would pause for input is if the code is all on the same line or if it is run line by line (instead of selecting all the code at once). See example from gtools using "ask":
silly <- function()
{
age <- ask("How old are you? ")
age <- as.numeric(age)
cat("In 10 years you will be", age+10, "years old!\n")
}
This runs with a pause:
silly(); paste("this is quite silly")
This does not wait for input:
silly()
paste("this is quite silly")
Any guidance would be appreciated to ensure I can still run my entire script and have it pause at readline without continuing. I am using R-studio and I have checked that interactive==TRUE.
The only other work-around I found is wrapping my entire script into one main function, which is not ideal for me. This may require me to use <<- to write to my environment.
Thank you in advance.

Make readline wait for input in R

I'm trying to make my code ask me for a "TRUE" or "FALSE" value before proceeding.
It currently works fine if I run it one line at a time, however when I run all the code at once in RStudio it simply proceeds without waiting for user input and records a value of "" for my parameter.
raw <- readline("TRUE or FALSE -- this is a validation run: ")
if (raw == "F" | raw == "FALSE" | raw == "False"){
validation <- F
} else{
validation <- T
}
rm(raw)
Ideally, I would like an answer that works regardless of how I run it -- RScript, source within RStudio, or running it (i.e. selecting the code and pressing run or ctrl-enter).
If you want to do this in interactive mode then you already have answers but not for use with Rscript. For that instance you need to send messages to the console with cat:
If this test file is named 'prompt.r' and is in the directory where you are working in a system console session:
cat("a string please: ");
a <- readLines("stdin",n=1);
cat("You entered")
str(a);
cat( "\n" )
Then you can run it from the command line as
$ Rscript prompt.r
If you want an all-purpose script then this would run your script under interactive conditions and my script for non-interactive ones:
if (interactive() ){raw <-
readline("TRUE or FALSE -- this is a validation run: ")
if (raw == "F" | raw == "FALSE" | raw == "False"){
validation <- F
} else{
validation <- T
}
rm(raw) } else{
# non-interactive
cat("a string please: ");
a <- readLines("stdin",n=1);
cat("You entered")
str(a);
cat( "\n" )}
Are you running the code by highlighting the lines and clicking run? If so, that could be your problem because R is line-by-line entering your code in the terminal.
Instead, write your script (or comment out the parts you're not testing) and click the source button. Then R waits for user response instead of inputting the line after readline() into readline().
I had the same problem as you, which prompted me to look for an answer. But then I tried this different method of executing the code and it worked.
The reason why readline is "not waiting for input" is, according to the manual (?readline):
In non-interactive use the result is as if the response was RETURN and
the value is "".
You have stumbled on one of the "surprising" features of R.
<rant>
Why readline() works in "interactive mode" only is a complete mystery for me, since it's a perfectly acceptable use case to ask for user input from within a script. Python, for instance, gives you the input(prompt) function which you may invoke whenever you need it.
</rant>
A relatively convenient way of getting around this mess is to define a function ("Every programming problem can be solved by yet another level of indirection"...):
user.input <- function(prompt) {
if (interactive()) {
return(readline(prompt))
} else {
cat(prompt)
return(readLines("stdin", n=1))
}
}
A positive side-effect is that you can add all sorts of nice input validation in user.input(). But I doubt that that was the intention behind the bizarre behaviour of readline().
Although it requires interactive mode, I found the askYesNo() function within the utils package to provide a nice, simple user interface for TRUE/FALSE (or more accurately Yes/No) questions. For example, the following code would produce the following dialog.
Yes returns TRUE
No returns FALSE
Cancel returns NA
Using svDialogs may let you do this.
It's not exactly using readline, but does achieve a similar outcome to what you're looking for.
The code won't run until the dialog box has been filled:
library(svDialogs)
raw <- dlgInput("TRUE or FALSE -- this is a validation run: ",Sys.info()["raw"])$res
if (raw == "F" | raw == "FALSE" | raw == "False"){
validation <- F
} else{
validation <- T
}
rm(raw)
You have to create a function set an "if" conditional sentence with "is.na()" then execute "readline()" again if the value entered is null.
see below:
readinteger <- function()
{
n <- readline(prompt="Enter an integer: ")
n <- as.integer(n)
if (is.na(n)){
n <- readinteger()
}
return(n)
}
print(readinteger())
rm(list=ls())

Resources