Multi-line command execution over remote SSH - ssh

I want to execute multiple lines of shell commands over remote ssh.
According to https://unix.stackexchange.com/questions/1459/remote-for-loop-over-ssh, I just need to use single quotes to execute a multi-line for loop. Here is what I tried:
ssh user#server ‘cd ~/Data; cwd=pwd; for i in `find 201806 -name "day_*"`; do echo $i; cd $i; a.sh; cd $cwd; done’
Since nothing happens, I am speculating that there is a syntax error that I must not be understanding. 201806 is the name of a folder in the Data directory, and I have tested that the command works without the ssh user#server. Any suggestions?

Try this
ssh -v user#server ‘cd ~/Data; cwd=`pwd`; for i in `find 201806 -name "day_*"`; do echo $i; cd $i; ./a.sh; cd $cwd; done’
Also, make sure your a.sh file have execute permission. -v option will give debugging messages about its progress.

Related

How to escape ANSI format on remote SSH command?

I wanted to change the title of the window using the command as described here over SSH, however I kept get getting the error:
033]sh: Hello: command not found
Connection to host closed.
with the command:
ssh.exe user#host -t 'echo -en "\033];Hello World\007"'
No matter how I try to escape them, it seems to somehow return error. Tried:
ssh.exe user#host -t 'echo -en "\\033];Hello World\\007"'
ssh.exe user#host -t "echo -en \'\\033];Hello World\\007\'"
Any idea how to fix this?

Sudo over SSH mixes up password tty and stdin

Setup:
Local *nix machine with a SQL script script.sql (Postgres).
Remote machine remote (Debian 7) with Postgres.
I can SSH in as some_user, who is a sudoer.
Anything with Postgres needs to be done as postgres user.
The server only listens on localhost:5432.
How do I execute script.sql on remote without copying it there first?
This works well:
ssh -t some_user#remote 'sudo -u postgres psql -c "COMMANDS FOO BAR"'
The -t flag means that sudo will ask for some_user's password correctly on the local terminal.
One thing remains, to be able to pipe script.sql to psql. This does not work:
ssh -t some_user#remote 'sudo -u postgres psql' < script.sql
It fails with the message:
Pseudo-terminal will not be allocated because stdin is not a terminal.
sudo: no tty present and no askpass program specified
Edit: simplified example
Postgres and psql don't seem to figure much in the problem. The following code has the same issues:
ssh some_user#remote xargs sudo ls < input_file
The problem seems to be: we need to send 2 inputs to sudo, both the password using a tty, and the stdin to pass to ls.
Edit: even simpler
ssh localhost xargs sudo ls < input_file
sudo: no tty present and no askpass program specified
Adding -t does not work:
$ ssh -t localhost xargs sudo ls < input_file
Pseudo-terminal will not be allocated because stdin is not a terminal.
sudo: no tty present and no askpass program specified
Adding another -t does not work either:
$ ssh -t -t localhost xargs sudo ls < input_file
<content of input_file>
<waiting on a prompt>
ssh -T some_user#remote "sudo -u postgres psql -f-" < script.sql
"-f-" will read the script from STDIN. Just redirect the file in there, and there you go.
Don't bother with -t option to ssh, you don't need a full terminal for this.
ssh -T ${user}#${ip} sudo DEBIAN_FRONTEND=noninteractive postgres psql -f- < test.sql
Use DEBIAN_FRONTEND=noninteractive for resolve no tty present or equivalent of your distribution.

Running ssh command and keeping connection

Is there a way to execute a command before accessing a remote terminal
When I enter this command:
bash
$> ssh user#server.com 'ls'
The ls command is executed on the remote computer but ssh quits and I cannot continue in my remote session.
Is there a way of keeping the connection? The reason that I am asking this is that I want to create a setup for ssh session without having to modify the remote .bashrc file.
I would force the allocation of a pseudo tty and then run bash after the ls command:
syzdek#host1$ ssh -t host2.example.com 'ls -l /dev/null; bash'
-rwxrwxrwx 1 root other 27 Apr 1 2005 /dev/null
bash-4.1$
You can try using process subsitution on the init file of bash. In the example below, I define a function myfunc:
myfunc () {
echo "Running myfunc"
}
which I transform to a properly-escaped one-liner echoed in the <(...) construct for process subsitution for the --init-file argument of bash:
$ ssh -t localhost 'bash --init-file <( echo "myfunc() { echo \"Running myfunc\" ; }" ) '
Password:
bash-3.2$ myfunc
Running myfunc
bash-3.2$ exit
Note that once connected, my .bashrc is not sourced but myfunc is defined and properly usable in an interactive session.
It might prove a little difficult for more complex bash functions, but it works.

Transfer files over SSH, then appended to another file

I'm trying to automate a script that copies a file from my local server to a remote server on the command line. I've done the research on scp and know how to copy the file to the remote server, but then I want to append that file to another.
This is my code:
scp ~/file.txt user#host:
ssh user#host cat file.txt >> other_file.txt
When I enter everything into the command line manually as such, everything works fine:
scp ~/file.txt user#host:
ssh user#host
cat file.txt >> other_file.txt
But when I run the script, only the file is copied, not appended to the end of other_file.txt. Help?
The second line of your code should be
ssh user#host "cat file.txt >> other_file.txt"
Three important points:
You don't want your local shell to interpret >> in any way (which it does if it's unquoted)
There is a remote shell which will interpret >> in the command correctly.
Final arguments to ssh are "joined" to form a command, not carried into an argv array as they are. It may be convenient but it also may lead to confusion or bugs: ssh cat "$MYFILE" and ssh "cat '$MYFILE'" both work in a common use case, but they both break for different values of $MYFILE.
You need to enclose the command to be run on the remote host in quotes. Otherwise, the redirection is being done locally rather than remotely. Try this instead:
scp ~/file.txt user#host:
ssh user#host 'cat file.txt >> other_file.txt'
Try this:
$ cat file.txt| ssh hostname 'cat >> other_file.txt'

How to make ssh-add read passphrase from a file?

I am trying to add a key to ssh-agent and want ssh-add to read the password from the key file I'm using. How is this possible?
How do I automate this process from the shell script?
Depending on your distribution and on the version of ssh-add you may be able or not to use the -p option of ssh-add that reads the passphrase from stdin in this way:
cat passfile | ssh-add -p keyfile
If this is not working you can use Expect, a Unix tool to make interactive applications non-interactive. You'll have to install it from your package manager.
I have written a tool for you in expect. Just copy the content in a file named ssh-add-pass and set executable permissions on it (chmod +x ssh-add-pass). You can also copy it to /usr/bin or /usr/local/bin to be accessible from the $PATH search.
#!/bin/bash
if [ $# -ne 2 ] ; then
echo "Usage: ssh-add-pass keyfile passfile"
exit 1
fi
eval $(ssh-agent)
pass=$(cat $2)
expect << EOF
spawn ssh-add $1
expect "Enter passphrase"
send "$pass\r"
expect eof
EOF
The usage is simply: ssh-add-pass keyfile passfile
Similar to the answer by kenorb, but doesn't save the secret in a file:
$ SSH_ASKPASS=/path/to/ssh_give_pass.sh ssh-add $KEYFILE <<< "$KEYPASS"
where ssh_give_pass.sh is:
#!/bin/bash
# Parameter $1 passed to the script is the prompt text
# READ Secret from STDIN and echo it
read SECRET
echo $SECRET
If you have you secret in a $KEYPASSFILE, read it into a variable first with
KEYPASS=`cat $KEYPASSFILE`
Also make sure that ssh_give_pass.sh is not editable by unauthorized users - it will be easy to log all secrets passed through the script.
Here is some workaround for systems not supporting -p:
$ PASS="my_passphrase"
$ install -vm700 <(echo "echo $PASS") "$PWD/ps.sh"
$ cat id_rsa | SSH_ASKPASS="$PWD/ps.sh" ssh-add - && rm -v "$PWD/ps.sh"
where ps.sh is basically your script printing your passphrase. See: man ssh-add.
To make it more secure (to not keep it in the same file), use mktemp to generate a random private file, make it executable (chmod) and make sure it prints the passphrase to standard output once executed.
On my Ubuntu system, none of the answers worked:
ssh-add did not support the -p option.
ssh-add ignored SSH_ASKPASS, insisting on prompting for the passphrase on the controlling terminal.
I wanted to avoid installing additional packages, especially expect.
What worked in my case was:
password_source | SSH_ASKPASS=/bin/cat setsid -w ssh-add keyfile
password_source isn't really a program: it just represents whatever feeds the passphrase to ssh-add. In my case, it is a program that executes setsid and writes the passphrase to its stdin. If you keep your passphrase in a file, you are responsible for making the simple modifications: I will not enable you to hurt yourself.
setsid was already installed, and detaches the controlling terminal so that ssh-add will not try to use it to prompt for the passphrase. -w causes setsid to wait for ssh-add to exit and make its return code available. /bin/cat has the same effect as the script Ray Shannon provided, but uses a standard tool instead of replicating its functionality with a script.
With this minimal changes worked for me this bash script of #enrico.basis
#!/bin/bash
if [ $# -ne 2 ] ; then
echo "Usage: ssh-add-pass passfile keyfile"
exit 1
fi
eval 'ssh-agent -s'
passwordToFileSSH=$1
pathFileSSH=$2
expect << EOF
spawn ssh-add $pathFileSSH
expect "Enter passphrase"
send "$passwordToFileSSH\r"
expect eof
EOF
The best way is to generate a key without a passphrase