These two ssh options:
ssh -o StrictHostKeyChecking=no -o NumberOfPasswordPrompts=0
I am interested in setting those using env variables, is there a way to do that?
export StrictHostKeyChecking=no
export NumberOfPasswordPrompts=0
but that's of course not quite right
The "proper" way to do this is within your ~/.ssh/config file, where you can make those global for all connections or you can restrict it by host (or a few more advanced things). I'm going to assume you can't do that but that you do still have the ability to alter your ~/.bashrc or whatever.
You can solve this by putting this in your ~/.bashrc or ~/.zshrc (or by running these lines before ssh):
SSH_ARGS=( -o StrictHostKeyChecking=no -o NumberOfPasswordPrompts=0 )
alias ssh='ssh "${SSH_ARGS[#]}"'
If you want explicit environment variables like what you're proposing in your question (e.g. $StrictHostKeyChecking) then you'll have to make a really ugly alias or function to convert them all to the final ssh call. Here's a solution that should work in bash but won't work in POSIX shell:
ssh() {
local SSH_VAR SSH_VAR_VALUE
for SSH_VAR in StrictHostKeyChecking NumberOfPasswordPrompts; do # expand this
SSH_VAR_VALUE="${!SSH_VAR}" # bash indirect expansion
if [ -n "$SSH_VAR_VALUE" ]; then
set -- -o "$SSH_VAR=$SSH_VAR_VALUE" "$#"
fi
done
command ssh "$#"
}
The above example only supports the two SSH variables named in the question. That line will likely have to get really long as it must explicitly name every option before the semicolon on the line with the # expand this comment.
This loops over every supported SSH variable and uses bash's indirect expansion to check whether it is in the environment (and not an empty value). If it is, a -o and the option name and its value are prepended to the start of the argument list ($#).
If you use zsh, you'll need zsh's parameter expansion flag P, replacing bash's ${!SSH_VAR} with zsh's ${(P)SSH_VAR}. Other shells may need to replace that whole "bash indirect expansion" line with eval "SSH_VAR_VALUE=\"\${$SSH_VAR}\"" (watch your quoting there, or that line can be dangerous).
Invoking command ssh prevents the recursion we'd get from calling ssh from within a function of the same name. command ssh ignores the function and actually runs the true ssh command.
Related
I am using AWS Beanstalk, in case it may be relevant to the question.
The issue that I have is that when I do from my local terminal:
ssh mozart-api printenv
I missing most of the enviroment variables, instead if I do:
ssh mozart-api
..wait to open..
printenv
I get all enviroment varibles as I was expecting.
At first I thought it could be an ssh configuration in server but can't find anything strange.
if I do:
ssh mozart-api "export hello=123 && echo $hello"
then it outputs 123, which means that variables can be set and queried, however I just cannot get the existing variables from the server.
This is causing an issue because I am preparing a script that will run a command in ssh on this server, but because the variables are not loaded the project fails to open the database.
I tried reimporting them in one liner:
ssh mozart-api "sudo chmod +777 /etc/profile.d/sh.local && (/opt/elasticbeanstalk/bin/get-config environment | jq -r 'keys[] as \$k | \"echo export \(\$k)=\(.[\$k])\"') > /etc/profile.d/sh.local && printenv"
But still can't see the new added variables.
ssh mozart-api executes a login shell, which probably sources one or more files that define your environment variables.
ssh mozart-api printenv executes printenv instead of a login shell, so the only variables you see are the ones you inherit from the parent process, not any of the variables defined in your shell configuration files.
When I am doing SSH to some machine inside the for loop it is doing the ssh but not able to execute further.
Code is like:
string=c01.test.cloud.com,c02.test.cloud.com
for i in $(echo $string | sed "s/,/ /g")
do
ssh -t -t AppAccount#$i
cd a/b/c
str2=x,y,z
done
I take it from your question that you expect cd a/b/c to run on a remote server? That's not what this script is doing. The call to ssh opens an SSH tunnel, and provides you an interactive terminal connection. It then waits for that connection to terminate. (I suspect if you pressed Control-D, the script would continue.) Your use of -t -t here is particularly strange. Why do you want to force a remote pty? This is making the problem worse (not that much, since it won't work anyway, but this seems the opposite of what you'd want).
I think this is the script you meant:
string=c01.test.cloud.com,c02.test.cloud.com
for i in $(echo $string | sed "s/,/ /g")
do
ssh AppAccount#$i 'cd a/b/c; str2=x,y,z'
done
(This won't do anything of course, but I assume your real script has more to it than setting a shell variable and exiting.) The point is that you ned to pass the script you want to run as a parameter to ssh. Otherwise it's going to spawn an interactive shell and wait for you to close it.
Note that if your script is very complicated, it can be very inconvenient to stick it all in a single-quoted string. If your internal script is in its own file, a simple way to handle this is with bash -s which reads a script from stdin:
cat some_script | ssh server 'bash -s'
You can also use bash Here docs to achieve the same thing, but that is likely getting too fancy for this use.
I am trying to do something like this inside ssh session:
Script
ssh remoteservername "
col=`sed -n "8p" /tmp/temp.txt`
echo $col>>/tmp/Ankur.txt
"
This is not working and it is printing empty line instead of text what I want to store in col variable, why so, and this is working:
ssh remoteservername "
sed -n "8p" /tmp/temp.txt>>/tmp/Ankur.txt
"
This Ankur.txt file is on the remote server....The main focus is how to get the output of the command inside a variable so that i can use it further.
Please tell how to make it work.
Thanks
When you use double quotes the variable names will get expanded before passing them, so $col is getting expanded locally before running on the remote server. You can either escape the $ like \$col or use single quotes around it, which is probably better since you want to use double quotes inside the command as well
ssh remoteservername '
col=`sed -n "8p" /tmp/temp.txt`
echo $col>>/tmp/Ankur.txt
'
Without changing the quotes
ssh remoteservername 'sed -n "8p" /tmp/temp.txt >> /tmp/Ankur.txt'
as you noted, still works, by redirecting the output directly into the file. This avoids the variable expansion problem from the double quotes above.
If you're going to have many steps though, you might want to just create a script on remoteservername and invoke that in your ssh command rather than doing a lot on the same command line.
You can use a local file to execute complex commands and to use variables in remote machine via SSH as shown below.
1. Create a input file 'input_file.txt'
#-- input_file.txt
col=`sed -n "8p" /tmp/temp.txt`
echo $col>>/tmp/Ankur.txt
2. Execute the commands of input file in remote server via SSH
ssh remoteservername "sh -s" < input_file.txt
I would like to set a local variable in a ssh command-chain that is only used in this environment:
#!/bin/sh
my_var='/tmp/wrong_file'
ssh user#server "my_var='/tmp/a_file'; cat $my_var;my_var=123;echo $my_var"
echo $my_var
This example the "outer" $my_var is used. How to fix this and use variables "in" the current ssh connection as locally defined? There is no need to change or access the external value '/tmp/wrong_file' in $my_var, as asked in Assign directory listing to variable in bash script over ssh.
You're using the wrong quotes. Parameter expansion is performed inside double quotes, but not inside single quotes.
#!/bin/sh
my_var=/tmp/wrong_file
ssh user#server 'my_var=/tmp/a_file; cat $my_var;my_var=123;echo $my_var'
First of all: The SSH shell and your local shell are completely different and do not exchange any environment variables. This is a good thing - consider environment variables such as LD_LIBRARY_PATH when using SSH between machines of different OS architecture.
IMHO the best solution for your problem is to encapsulate your commands into a shell script on the remote side, then maybe start it with parameters. E.g.:
Remote:
myscript.sh contains:
#!/bin/sh
MY_FILE="$1";
echo "Contents of §MY_FILE:"
cat $MY_FILE
Local:
RUn something like
export REMOTE_FILE='/path/to/it'
ssh user#server "/path/to/myscript.sh '$REMOTE_FILE'"
I want to be able to just ssh to a server where I cannot modify profiles and set up the environment with several commands before getting the usual interactive session.
Any ideas?
I've been using an expect script with an "interact" command at the end - which works for most things but is clumsy and breaks some console apps. Also been extermienting with empty-expect and socat. Any other suggestions?
If you're able to write somewhere on the filesystem, you may be able to invoke bash with a custom rc file like this:
ssh me#example.com -t bash --rcfile /home/user/my_private_profile -i
Note that this appears to only work for interactive shell, not login shells. The -t option to ssh makes it allocate a pty even though you're specifying a command.
If you can't write to the filesystem anywhere, you could use a subshell to supply a named pipe as the rcfile:
$ ssh ares -t "bash --rcfile <(echo 'FOO=foo';echo 'BAR=bar') -i"
axa#ares:~$ echo $FOO
foo
axa#ares:~$ echo $BAR
bar