Use stdin from within R studio - linux

When I try the following:
f<-file("stdin")
lines<-readLines(f)
from within R-studio on Ubuntu I can input text but unable to terminate it. Ctr+C/D, random hitting keyboard won't help. It simply hangs
I only found the followin so far
How to input EOF in stdin in R?
but no help there - had to kill R-studio.
Anybody have explanation what is wrong?

Presumably, Rstudio is redirecting stdin, so that it cannot be properly accessed as "stdin" or "/dev/stdin" any longer. However, stdin() still works.
I was still unable to actually type Ctrl+D. But it is possible to read a fixed number of lines:
> a <- readLines(stdin(), n=2)
Hello
World
> a
[1] "Hello" "World"
I've also discovered a hack that may help for interactive debugging. Let's say, you have at most 10 lines in your manual examples. Then you can do
> a <- readLines(stdin(), n=10)
abc
def
ghi
# and now just keep pressing ENTER
...
> a <- a[a != ""]
> a
[1] "abc" "def" "ghi"
If you run the same code in an environment where Ctrl+D is available, it also properly terminates the input.
Caveats: but stdin() does not work with Rscript: you'd have to switch back to file("stdin"). Furthermore, in some environments, if you use readLines with n=1 to read the file line-by-line, you may end up reopening the file and getting the first line every time. It seems that putting everything into a file and reading the whole file at once with e.g. read.table is a much more robust way of developing with Rstudio.

Related

Is there an end= equivalent for inputs?

So as I'm sure you know there's a specific operator for print() functions called end.
#as an example
print('BOB', end='-')
#would output
BOB-
So is there something like this for inputs? For example, if I wanted to have an input that would look something like this:
Input here
►
-------------------------------------------------------
And have the input at the ► and be inside the dashes using something like
x = input('Input here\n►', end='-------')
Would there be some equivalent?
EDIT:
Just to be clear, everything will be printed at the same time. The input would just be on the line marked with the ►, and the ---- would be printed below it, but at the SAME time. This means that the input would be "enclosed" by the ---.
Also, there has been a comment about curses - can you please clarify on this?
Not exactly what you want, but if the --- (or ___) can also be on the same line, you could use an input prompt with \r:
input("__________\r> ")
This means: print 10 _, then go back \r to the beginning of the line, print > overwriting the first two _, then capture the input, overwriting more _. This shows the input prompt > ________. After typing some chars: > test____. Captured input: 'test'
For more complex input forms, you should consider using curses.
When using basic console IO, once a line has been ended with a newline, it's gone and can't be edited. You can't move the cursor up to do print anything above that last line, only add on a new line below.
That means that without using a specialized "console graphics" library like curses (as tobias_k suggests), you pretty much can't do what you're asking. You can mess around a little with the contents of the last line (overwriting text you've already written there), but you can't write to any line other than the last one.
To understand why console IO works this way, you should know that very early computers didn't have screens. Instead, their console output was directly printed out one line at a time on paper. While some line printers could print several characters on the same spot (to get effects line strikethrough or underline), you couldn't unprint anything once it was on the paper. Furthermore, the paper feed only worked in one direction. Once you had sent a newline character that told the printer to advance the paper, you couldn't go back to an old line again.
I believe this would solve your problem:
print(f">>> {input()} ------")
OR
print(f"{input(">>>")} ------")
F-strings are quite useful when it comes to printing text + variables.

Filtering by length of lines in file giving unexpected result

I am working my way through Learn You a Haskell for great good. I am currently on the files and streams section of Chapter 9. For some reason, when I try to pipe code into one of the example Haskell programs, I do not get the same output as the book. Using ConEmu for Linux commands on Windows. For example, I have the program that only prints out strings that are less than 10 characters with the code below (short_lines.hs):
main = interact $ unlines . filter ((<10) . length) . lines
I am going to be passing this file (short_long.txt):
i'm short
so am i
i am a loooooooooong line!!!
yeah i'm long so what hahahaha!!!!!!
short line
loooooooooooooooooooooooooooong
short
Here is the command:
cat short_long.txt | runhaskell short_lines.hs
Here is my output:
so am i
short
The book says that the output is the following:
i'm short
so am i
short
I believe this has to do with the handling of the newline character but I can't figure this out since lines should have removed the newline characters before filtering. It works with manual input but not with piping. Why am I getting a different output? Am I doing something wrong? I tried removing trailing newline characters in Atom editor but it didn't change anything. Any help on why I am not getting the expected result and what I could do to get the expected result would be greatly appreciated. Thank you!
The default newline mode for stdin is nativeNewline, which chooses its behavior based on what it believes your OS to be. I suspect that it has (wrongly) decided you are on a Unix system and it therefore should not do CRLF conversion; thus when given a Windows-style file each line has a trailing '\r' character. Try using
import System.IO
main = do
hSetNewlineMode stdin universalNewlineMode
interact $ unlines . filter ((<10) . length) . lines
to force CRLF conversion and see if that gets you the expected results.
I can reproduce your problem on my Unix system by converting a text file to DOS mode before giving it to your program. Having done so, my suggested fix gets the desired behavior.
I found out that I can change the line ending style from Windows-CRLF to Unix-LF on Atom editor. Currently it is located on the bottom and simply says CRLF or LF. You can click on it to choose a different line style. For this book, that is what I will use for simplicity's sake. However, I believe that amalloy's answer is a better long-term universal approach to IO.

Haskell does not return from getLine

For some reason, Haskell on my machine does never return from any getLine call. For instance, I tried to run the following code straight from Learn You a Haskell for Great Good:
main = do
putStrLn "Hello, what's your name?"
name <- getLine
putStrLn ("Hey " ++ name ++ ", you rock!")
When I run it, the first line is printed, and I see my input when I type a name, however when I press Enter the program just blocks there and never prints the final line.
How should I fix this?
edit: I am running it from the Sublime IDE, maybe that has something to do with it
After doing a quick search on how Sublime runs programs, I found a youtube video (edit: and this SO post) which says that Sublime's "run program" functionality can only show output and isn't capable of reading input.
So it looks like you'll have to run your program from the command line or from within GHCi using :main. The latter might be the most convenient as Sublime actually supports a GHCi tab, so you can still do everything from within Sublime.
This seems to be a limitation in Sublime's Build command (assuming that this is what you're using).
Sublime executes the script using runhaskell, but apparently, it doesn't capture STDIN (which makes kind of sense - build results are usually read-only and not an interactive session).
Workaround: run your script from the command line with
runhaskell script.hs
and everything works as expected

How do I use getContents to take input from the command line?

My program allows the user to specify a file which is read as input, however this is optional. If the user does not specify a file, I'd like to read input in from the command line.
I have this so far:
main :: IO()
main = do
(opts, mbArgs) <- parseCmdLine
input <-
case mbArgs of
Nothing -> getContents
Just file -> readFile file
This doesn't seem to be working. When a user doesn't stipulate a file, they are able to enter input, but there seems to be no way of terminating so that the program can then work on that input.
I thought that you had to press Ctrl+D, but that doesn't do anything.
Thanks for any help.
In a typical Unix-like terminal (such as Cygwin, at least in Cygwin's rxvt; not sure about the Windows Command Prompt), a Ctrl+D only sends EOF when you're at the start of a line. If you hit Enter and then Ctrl+D, it should work. If you want to send EOF without a newline, hit Ctrl+D twice in a row.
If it's not that, then there's presumably some other problem with your terminal; the code looks fine.
I'm going to write hammar's comment as an answer.
For me on windows, hitting ctrl+Z crtl+Z enter worked.

How do I erase printed characters in a console application(Linux)?

I am creating a small console app that needs a progress bar. Something like...
Conversion: 175/348 Seconds |========== | 50%
My question is, how do you erase characters already printed to the console? When I reach the 51st percentage, I have to erase this line from the console and insert a new line. In my current solution, this is what happens...
Conversion: 175/348 Seconds |========== | 50%
Conversion: 179/348 Seconds |========== | 52%
Conversion: 183/348 Seconds |========== | 54%
Conversion: 187/348 Seconds |=========== | 56%
Code I use is...
print "Conversion: $converted_seconds/$total_time Seconds $progress_bar $converted_percentage%\n";
I am doing this in Linux using PHP(only I will use the app - so please excuse the language choice). So, the solution should work on the Linux platform - but if you have a solution that's cross platform, that would be preferable.
I don't think you need to apologize for the language choice. PHP is a great language for console applications.
Try this out:
<?php
for( $i=0;$i<10;$i++){
print "$i \r";
sleep(1);
}
?>
The "\r" will overwrite the line with the new text. To make a new line you can just use "\n", but I'm guessing you already knew that.
Hope this helps! I know this works in Linux, but I don't know if it works in Windows or other operating systems.
To erase a previously printed character you have three options:
echo chr(8) . " "; echoes the back character, and will move the cursor back one place, and the space then overwrites the character. You can use chr(8) multiple times in a row to move back multiple characters.
echo "\r"; will return the cursor to the start of the current line. You can now replace the line with new text.
The third option is to set the line and column of the cursor position using ANSI escape codes, then print the replacement characters. It might not work with all terminals:
function movecursor($line, $column){
echo "\033[{$line};{$column}H";
}
\r did the trick.
For future reference, \b does not work in PHP in Linux. I was curious - so I did a couple of experiments in other languages as well(I did this in Linux - I don't know if the result will be the same in Windows/Mac)..
\b Works in...
Perl
Ruby
Tcl - with code puts -nonewline "Hello\b"
\b Doesn't work in
PHP - the code print "Hello\b"; prints out Hello\b
Python - code print "Hello\b" prints out Hello<new line> . Same result with print "Hello\b",
I'm not sure if it's the same in Linux but in Windows console apps you can print \r and the cursor will return to the first left position of the line allowing you to overwrite all the characters to the right.
You can use \b to move back a single character but since you're going to be updating your progress bar \r would be simpler to use than printing \b x number of times.
This seems to be pretty old topic but I will drop my 5 into.
for ($i; $i<_POSITION_; $i--) {
echo "\010"; //issue backspace
}
Found this on the internet some time ago, unfortunately don't remember where. So all credits goes to original author.
to erase a previously printed character, I print a backspace after it:
print "a"
print "\b"
will print nothing (actually it will print and then a backspace, but you probably won't notice it)

Resources