Remote script skips "read" command

This script is supposed to display a file ( crontab ), ask the user if they wish to update the file, then it goes through an update routine.

#!/bin/bash
 FILE=/etc/crontab
  
 tail -5 $FILE
 
 echo -n "Does crontab need updating"
 read HOURS

...routines ....etc...

Runs locally fine but does not pause for input if I do:

ssh user@hostname < hours.sh

If I do this:

ssh user@hostname 'echo "type var";read var;echo $var'

It stops, get my input, then echoes var.

Ideas?

Thanks for reading!

Bubnoff

UPDATE: Here's something:
output from script:

stdin: is not a tty

I'm not entirely sure of what you're asking here. Could you give another shot at explaining what the problem is?

If you're wondering why this doesn't work:

ssh user@hostname < hours.sh

and hours.sh contains your "echo..." commands then the reason is because when you redirect input into a command from a file, stdin is already opened, and ssh can't allocate a pseudo-tty when stdin is already opened.

My ssh version actually tells me this - "Pseudo-terminal will not be allocated because stdin is not a terminal."

The reason the second code sample works:

ssh user@hostname 'echo "type var";read var;echo $var'

is because you're passing the "echo" string as a command to run on the remote machine, and stdin is still free to be allocated to a local pseudo-tty.

How would I get the script to catch my keyboard input with read when run remotely?

I've tried the '-t' and '-T' options to ssh with no success.

I don't think you can both have stdin coming from the redirected file and also from the keyboard.

So, the solution is to put the script on the remote server, and execute it there.

That'd work except there's a lot of machines to go through.

I wanted to do something to the effect:

for i in {10..55};do ssh root@10.10.18.$i < hours.sh;done

I don't exactly know what the crontab files will contain and writing a regex
for the possibilities seems a bit daunting. I could add a scp in there, but at that point I'm losing another step of automation.

I have to update an armada of machine's crontab files based on certain conditions. I was hoping to just "tail" the pertinent section, then have routines carry out actions based on my input ...rather than trying to have the script figure it out via regex. Especially since a regex would require more familiarity with the possibilities.

I may need to re-think this from the beginning and take a different tack.

So, outside of copying the script, this is not possible?

Thanks for your input.

---------- Post updated at 07:59 PM ---------- Previous update was at 07:12 PM ----------

From the ssh man page:

-t      Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be
 very useful, e.g. when implementing menu services. Multiple -t
             options force tty allocation, even if ssh has no local tty.

This almost works:

ssh -t -t root@10.10.17.25 < testread.sh

It does wait for me to type, but then stalls until <ctrl>-c.

can't you do something like?

ssh user@hostname "$(cat hours.sh)"
1 Like

As it turns out ...yes! It works ...but how? I "get" the $() and quoting construct but am wondering how this executes.
This isn't documented anywhere I looked. EDIT: Yes, I know that ssh executes stuff in quotes and am aware that $() is the
newer "backticks" construct. Specifically, how does this nested
construct with cat put the script on the correct tty/pseudo-tty to capture my input while executing my local script?

-- wait ---

I think I'm beginning to understand this ....

One note: This doesn't execute as expected:

read -p "Message from the beyond" VAR

You have to do this instead:

echo "Message from the beyond"
read VAR

Thanks dude!

Bub

Its called command-substitution (a feature of KSH).
Instead of typing the whole script on the command line, you just put it in a file and then use command-substitution to send all the commands as an argument to ssh instead of redirecting stdin.
This way your stdin is still linked to your terminal and you can send input to the script.

So, this:

ssh user@hostname 'echo "type var";read var;echo $var'

And this, are effectively same:

> cat hours.sh
echo "type var";
read var;
echo $var;

> ssh user@hotsname "$(cat hours.sh)"

I understand the command-substitution construct $(), but was thrown by the "cat". It makes perfect sense now that I've had a chance to think about it. I was not connecting execution of the script remotely with "cat"ting the script locally using command-substitution. I was thinking in terms of esoteric features of ssh rather than a common feature of bash.

Thanks for your time!

Bub