Preliminary note
It seems your ssh host does not ask for password or passphrase. My answer assumes it really does not.
Analysis
I try a file for password, the command exits immediately.
$ ssh -t -q host "sudo -S -i -u user" <password.txt 2>&1
This happens because all the input the remote side gets comes from the stdin of your local ssh and you have redirected this; so all the input comes from password.txt. Additionally -t does not work with stdin of ssh not being a tty (you're not seeing the warning from ssh because of -q), so the remote shell spawned by sudo -i does not see a tty, it behaves like a shell being piped to: it does not print prompts, it exits when it detects "end of file" (EOF) on its stdin. If you placed shell code after the actual password in password.txt then the remote shell would run it and exited anyway.
You could use -tt to force tty allocation on the remote side (no need for -S in sudo then) and then you would even see a prompt from the remote shell and the shell would not exit by itself (detecting "EOF" on a tty is different); you wouldn't be able to type commands to it though, because ssh would not relay input from its (local) tty, it would only read from password.txt.
I modify the command using something like below, i.e., send the file first, then switch to stdin.
(cat password.txt ; cat) | ...Although it works, it does not show the prompt
Again, -t does not work with stdin not being a tty, so … | ssh -t … is futile here.
Usefulness of using -tt in this case is discussed just below.
Poor man's solution
An improved version of your last try is like this:
cat password.txt - | ssh -tt -q host "sudo -i -u user"Now there is a tty on the remote side, but there are also problems:
- The password gets to the remote tty before
sudotells it not to echo input, so the remote tty echoes the password andsshprints it locally. - Command line editing is provided by the local line discipline. It respects the size of the prompt coming from the remote side, it can erase a word (usually with Ctrl+w) or the whole line (usually Ctrl+u), but there's not much more it can do. The command line editor of the remote shell will get input only after you press Ctrl+d or Enter (or Ctrl+j or Ctrl+m). E.g. if the remote shell supports retrieving commands from history with ↑ then you will need ↑Ctrl+d to actually see it "kinda working" and it will look ugly.
- The local tty echoes input before it gets to
cat(upon Enter or so), then the remote shell (or tty) echoes it again. - Characters generated by Ctrl+d, Ctrl+c or Ctrl+z don't get to the remote side, they get intercepted by the local tty and "act" locally (see this answer).
- The remote tty does not know the size of your local tty.
- Possibly more.
We can solve or mitigate some of these problems:
stty raw -echo; (sleep 2; cat -u password.txt -) | ssh -tt -q host "sudo -i -u user"; stty saneStill this solution is not perfect.
About sshpass
In a comment you were given a suggestion to look at sshpass. In my tests (in Ubuntu) sshpass did not solve your problem.
Yes, sshpass can feed a password to ssh or (with the right -P) to another tool (e.g. sudo). It does this by providing a separate tty for the tool. Sane tools asking for password print a prompt to their /dev/tty and read a response from therein. sshpass is in control of the tty it gave the tool, it listens for a prompt and reacts by "typing" the password. But sshpass lets the tool inherit stdin, stdout and stderr, it does not try to act as a relay there, it only changes what tty the tool will reach by opening /dev/tty.
This means sshpass works well with tools I described as "sane". ssh is sane, (local) sudo is also sane. Still, if we do something like
sshpass -fpassword.txt … ssh -t …'sudo …'(remember the assumption: our ssh does not ask) then the remote sudo will sanely use the tty provided by the SSH server, but the local ssh will use its stdout for writing arbitrary bytes generated by the remote side, and stdin for reading bytes to send to the remote side; it will not use its /dev/tty for this. In effect sshpass neither will see the prompt from sudo, nor be able to send anything to sudo.
Solution
The problem can be solved with expect. Basic example:
expect -c 'trap { set rows [stty rows] set cols [stty columns] stty rows $rows columns $cols < $spawn_out(slave,name)} WINCHlog_user 0set pw [exec cat password.txt]spawn ssh -t -q host "sudo -i -u user"expect "assword"send $pwsend "\n"interact'(The trap credited to this other answer.)
Note the line expect "assword" tells expect what to expect as (a part of) the prompt and you may need to change it. E.g. if your remote sudo is localized and asks for password in a language other than English then you should adjust the line accordingly.