(Bash) Piping echo into node disables program keyboard input - node.js

So I am using node.js' built-in debugger and trying to skip the "break on first line" that it performs by passing in a delayed "c" keypress (c=continue) using echo, as such:
(sleep 1; echo -ne 'c\n') | node debug ~/src/main.js
It works as expected, but the node debugger no longer seems to accept keyboard input afterwords. I assume the piping in bash is doing something to cause node to ignore the keyboard. Anyone know how I can achieve the same result but maintain keyboard input to the node program?

Because node is being run in a pipeline, its input file descriptor is open to the pipeline, not to the console.
A common way to feed input to a process and then allow the user to interact is to use expect or pexpect.

Related

Why we use -i or --interactive in the Node.js?

Why we use -i or --interactive in Node.js if we can easily jump into the REPL with just a simple command node ?
I have read the documentation but the documentation is a little bit confusing:
Reference Link
Opens the REPL even if stdin does not appear to be a terminal.
I understand the part Opens the REPL but didn't understand what does even if stdin does not appear to be a terminal mean ?
When executing node in a text terminal by itself, the program will provide a REPL for interactive use by a human. However, it might be the case that node is not run in a terminal, or that it was given a script to execute in a non-interactive fashion, which makes node run the given script without providing a REPL. For example, this would likely be the case for a Node.js child process which is given input and output streams between the parent process and the child process. As another example, the command below will not execute node in interactive mode:
echo "console.log('Hello');" | node
The -i option is designed to override this automatic decision, by forcing node to provide a REPL regardless of whether it has detected the presence of a text terminal. This may be particularly useful for making non-user-facing programs which streamline the REPL's inputs and outputs to another application.
Node.js itself provides an additional layer on top of input and output streams for those which are associated with a text terminal. According to the TTY module:
When Node.js detects that it is being run with a text terminal ("TTY") attached, process.stdin will, by default, be initialized as an instance of tty.ReadStream and both process.stdout and process.stderr will, by default be instances of tty.WriteStream.
If you run node and type in process.stdin.isTTY, it will output true. The following command, on the other hand, will print undefined:
echo "console.log(process.stdin.isTTY)" | node

Automate installation of binary in linux

I have a Bourne-Again shell script text executable named engine.bin that I want to install.
If I install the executable manually ./engine.bin I get a screen with the EULA I have to accept (by pushing space), then accept it by writing yes and then enter the installation path by typing /usr/local/engine.
Now I want to do the installation automatically through provisioning scripts without manual interaction. Is there a way to do this? I do not know if the installer accepts any parameters, unfortunately the thing is undocumented.
Based on the suggestion of bill-agee and jgr208 I wrote the following which is working for me:
#!/usr/bin/expect -f
set timeout -1
spawn /tmp/engine.bin
expect {
-gl "*Press SPACE or PAGE DOWN key to continue, U or PAGE UP key to scroll back*" { send -- " "; exp_continue }
-gl "*yes/no*"
}
send -- "yes\r"
expect -gl "*press ENTER to accept the default*"
send -- "/tmp/tce\r"
expect eof
If the executable allows you to spam input at it without waiting for each separate prompt to appear, you might be able to accomplish this with bash.
For example, this script will run program_that_takes_several_lines_of_input.py and send it four lines of input - three with text and one blank line:
#!/bin/bash -eux
./program_that_takes_several_lines_of_input.py <<EOD
first line
one enter keypress later
yet another line of input after the empty line above
EOD
If you need to stop and wait for each prompt to appear, the cram Python package may be a good fit for this scenario - I find it useful for tasks like this where you only need to send a few lines of input, but each line of input is different.
See:
https://bitheap.org/cram/
https://pypi.python.org/pypi/cram
Expect would also work, but I find that I reach working solutions a bit faster when using cram than with Expect.
pexpect is a great choice as well! See:
https://pexpect.readthedocs.org/en/stable/

How to start new gnome-terminal with blocking call?

I need to open a new terminal from my script but I want to wait for that terminal to exit before continuing with the rest of the script. I know that
gnome-terminal -e 'nano test.txt'
opens a new terminal window with "test.txt" opened in nano, but the calling script does not get blocked. Is there a way to wait for the new terminal to exit, before continuing the original script?
For the benefit of the reader: The answer from #Feiteira used to be the correct answer, but is no more supported by gnome-terminal. Option --disable-factory got removed from gnome-terminal.
To explain the different observation of several people here:
gnome-terminal only blocks, if it is the first instance of it. This single instance then acts as a server for all future invocations of gnome-terminal. Those other gnome-terminal calls then hand everything over to this server and immediately terminate. So you can observe both behavior: "blocking" (when it is the one-and-only single instance) and "nonblocking" (when another instance is already running).
There is a wrapper, for example used by Ubuntu 16.04, which emulates this missing option. However this wrapper is complex. This is done by starting another server (with another service name). And for this server, the same assumption holds (you can attach other gnome-terminals to this server, and those others then come back immediately as well).
My suggestion is to stop using gnome-terminal and to switch to something, which works right out of the box. For example xfce4-terminal officially supports all those little absolutely necessary options for a mature terminal window:
xfce4-terminal --disable-server -x nano test.txt
Also xfce4-terminal introduces --hold which allows you to see the output of a command. Sadly --hold has a bug (at least under Ubuntu 16.04), which causes it to (often) truncate the output (the terminal is closed too early if a command terminates, so all still buffered output of the PTY does not make it to the window. This is a very well known common bug if you are not careful enough with PTYs).
The option you want is: --disable-factory
gnome-terminal --disable-factory ...
You could use && for instance (also see What is the purpose of "&&" in a shell command?):
gnome-terminal -e 'nano test.txt' && sleep 5 && echo "Done"

Running a node.js process in background after giving inputs to it

I have this node.js server which, once spawned, expects some input from stdin. The inputs shouldn't be given straight away: I need to wait for some event before giving them (e.g. a connection from somebody). If I give the commands and close the shell, the server shuts itself down. I would like to give the input to the server and close my shell (effectively leaving the server running).
I know that to run a process in background I need to do for example node my_server.js &, but this prevents the input from the command line. I would like to give this input AND then put it in background. Modules like forever puts it in the background automatically without letting me giving the inputs through stdin.
Moreover putting the script in background kills anyways the server when closing the shell.
Any suggestion?
Thanks
I did a quick test just using gedit in Ubuntu 12.04, and it worked.
Start your node app like so "node app.js arg1 arg2" however you want to and hit enter to start the program. Then hit CTRL-z once your program has started running. This gives you the terminal back but stops the process in the background. To let it run in the background now, simply "bg" and hit enter. This will let the process keep running now but in the background.
You can confirm you are still up with the command "ps -ef | grep node" which should show your program still running.
However, this does still leave the node process attached to the terminal window so when you close the terminal window it will close the process. But I think this will get you most of what you seem to be looking for quick and easy.
You asked for any suggestion, so here it is: make your server able to start without user interaction. The simplest way to do it is probably to create a file containing exactly the input needed by the server, then starting it like this:
node my_server.js < my_input.txt &
If the input needed depends on what the server outputs (ouch), use expect(1). If possible, subvert the whole thing and use a module like commander to get your inputs from the command line instead of stdin.

Redirecting stdin through a FIFO

I'm running a server app (written in Java) under GNU/Linux which takes input (from stdin, I guess) and interprets it to run some commands. I dont want to run the app inside a terminal window (I'd like to run a daemon), but I'd still like to be able to input commands whenever I want to. I thought I might be able to do that using fifos, so I created it using mknod. The problem is cat fifofile > java... and cat fifofile | java ... fail with a "file not found" error for some reason.
Using only cat to read and write and the fifo works flawlessly.
Is there any way to fix this, or any other way to achieve the same goal?
So, Minecraft? The best way to do this is to have a bona-fide tty for the console part of the application. screen is an easy way to do that.
Have you tried java < fifofile? What about something like exec 3<&0; exec 0<fifofile; java?
What shell are you using? You might be able to use process substitution or coprocesses if you're using a shell that supports them.

Resources