Shell: write a script that gets executed on stdin wait - bash

I have this command command that at some point, returns: Press Enter to continue.
I would like to write a script that calls command, reads the so-far command output, does something with it when Press Enter to continue arrives, and simulates an enter key-press when this is done.
Any chance I can achieve that? :-D
Something like:
myscript | command > output
with myscript
#!/bin/bash
cp output output2 # output2 should only contain the output until Press Enter to continue
echo -ne '\n'
except it doesn't work! :-)

Ideally you should use expect command to achieve that, example code:
#!/usr/bin/expect
set timeout 600
spawn command
expect "Press Enter to continue" { send "\r" }
Note: Replace command with your command.
then save it into the script, make it executable and run it.
Check: man expect for further information.
On OS X install via: brew install expect.

Related

linux - bash: pipe _everything_ to a logfile

In an interactive bash script I use
exec > >(tee -ia logfile.log)
exec 2>&1
to write the scripts output to a logfile. However, if I ask the user to input something this is not written to this file:
read UserInput
Also, I issue commands with $UserInput as parameter. These command are also not written to the logfile.
The logfile should contain everything my script does, i.e. what the user entered interactively and also the resulting commands along with their output.
Of course I could use set -x and/or echo "user input: "$UserInput, but this would also be sent to the "screen". I dont want to read anything else on the screen except what my script or the commands echo.
How can this be done?

Send echo command to an external xTerm

I have a bash script, and I want to be able to keep a log in an xterm, and be able to send echo to it anytime.
How would I do this?
Check the GPG_TTY variable in your xterm session. It should have the value similar to
GPG_TTY=/dev/pts/2
This method should be available for terminals that support GNU Pinentry.
Another option to determine the current terminal name is to use
readlink /proc/self/fd/0
The last method applies only to Linux
Now if your bash script implements a command
echo "Hello, world!" > /dev/pts/2
This line should appear on the xterm screen.
I managed to make a console by running an xterm with a while loop clearing the screen, reading the contents of the log file, pauseing for a second, then looping again. Here was the command:
xterm -T Console -e "while true: do cls && cat ${0}-LOG.txt && sleep 1; done"
Then to send something to the console:
echo -e "\e[91;1mTest" >> ${0}-LOG.txt
And the console will update each second.

Pipe Code to sh — Script not waiting on read Command

Content of my remote file:
#!/bin/sh
read foo && echo "$foo"
What I’m doing locally in my terminal:
$ curl -fLSs http://example.com/my-remote-file.sh | sh
What I’m expecting:
The downloaded script should prompt the user to enter something and wait for the users input.
What actually happens:
The downloaded script skips the read command and continues executing.
Question:
How can I prompt the user to input something from a script that is downloaded via curl? I know that sh <(curl -fLSs http://example.com/my-remote-file.sh) is working, but this is not POSIX compliant and I’d like to achieve that.
The problem is that stdin is reading from curl, rather than the keyboard. You need to change your script to instruct it to read specifically from the terminal, like this:
read input < /dev/tty
echo $input

Why isn't this command returning to shell after &?

In Ubuntu 14.04, I created the following bash script:
flock -nx "$1" xdg-open "$1" &
The idea is to lock the file specified in $1 (flock), then open it in my usual editor (xdg-open), and finally return to prompt, so I can open other files in sequence (&).
However, the & isn't working as expected. I need to press Enter to make the shell prompt appear again. In simpler constructs, such as
gedit test.txt &
it works as it should, returning the prompt immediately. I think it has to do with the existence of two commands in the first line. What am I doing wrong, please?
EDIT
The prompt is actually there, but it is somehow "hidden". If I issue the command
sudo ./edit error.php
it replies with
Warning: unknown mime-type for "error.php" -- using "application/octet-stream"
Error: no "view" mailcap rules found for type "application/octet-stream"
Opening "error.php" with Geany (application/x-php)
__
The errors above are not related to the question. But instead of __ I see nothing. I know the prompt is there because I can issue other commands, like ls, and they work. But the question remains: WHY the prompt is hidden? And how can I make it show normally?
Why isn't this command returning to shell after &?
It is.
You're running a command in the background. The shell prints a new prompt as soon as the command is launched, without waiting for it to finish.
According to your latest comment, the background command is printing some message to your screen. A simple example of the same thing:
$ echo hello &
$ hello
The cursor is left at the beginning of the line after the $ hello.
As far as the shell is concerned, it's printed a prompt and is waiting a new command. It doesn't know or care that a background process has messed up your display.
One solution is to redirect the command's output to somewhere other than your screen, either to a file or to /dev/null. If it's an error message, you'll probably have to redirect both stdout and `stderr.
flock -nx "$1" xdg-open "$1" >/dev/null 2>&1 &
(This assumes you don't care about the content of the message.)
Another option, pointed out in a comment by alvits, is to sleep for a second or so after executing the command, so the message appears followed by the next shell prompt. The sleep command is executed in the foreground, delaying the printing of the next prompt. A simple example:
$ echo hello & sleep 1
hello
[1] + Done echo hello
$
or for your example:
flock -nx "$1" xdg-open "$1" & sleep 1
This assumes that the error message is printed in the first second. That's probably a valid assumption for you example, but it might not be in general.
I don't think the command is doing what you think it does.
Have you tried to run it twice to see if the lock cannot be obtained the second time.
Well, if you do it, you will see that it doesn't fail because xdg-open is forking to exec the editor. Also if it fails you expect some indication.
You should use something like this
flock -nx "$1" -c "gedit '$1' &" || { echo "ERROR"; exit 1; }

How to use rmt command in tcl script? (Expectk)

I am trying to create a tcl script that uses Expectk and the rmt command. I can spawn an rmt process and get the correct process ID, but no send command I use works. I noticed from the man page that the normal send command is defined for a different purpose, so I should be using exp_send.
Here is the script. All I want to do is get the status of the tape drive:
#!/bin/sh
# Restarts using wish in the command search path
exec expectk "$0" -- "$#"
set stored_id [spawn "rmt"]
exp_send -i $stored_id "O/dev/nst0\r"
exp_send -i $stored_id "S\r"
Edit: This is how you use the command from the command line normally:
$ rmt
O/dev/nst0
S
A0
^C
The "A0" is the response from the command, and ^C is me pressing Ctrl-C to exit the rmt command.
Try sending \n\r at the end of each command. The following kind of works for me (note, using raw expect):
spawn "rmt"
send "O/goo/bar\n\r"
expect "E22" {
puts "Error!!!"
}
#AlexanderL.Belikoff put me on the right track.
I didn't really understand the man page for this command at all at first. The following seems to work to open up the device for reading and writing, and that it gets the status of the device. The status will automatically be put on the screen, but the "Got the status" part just means the command executed successfully.
#!/bin/sh
# Restarts using wish in the command search path
exec expectk "$0" -- "$#"
spawn "rmt"
exp_send "O/dev/nst0\r"
exp_send "O_RDRW\r"
expect "A0" {
puts "Success!"
}
exp_send "S\r"
expect "A" {
puts "Got the status"
}

Resources