Home > Blockchain >  Is it possible using "su -c" with multiple commands but in one session?
Is it possible using "su -c" with multiple commands but in one session?

Time:11-05

I am trying run the following two command in one command.

eval "$(ssh-agent)"
ssh add ~/.ssh/id_rsa

I tried with many possible solutions:

su username -c "{ eval $(ssh-agent -s) }; ssh-add ~/.ssh/id_rsa"
su username -c "eval $(ssh-agent -s)" ; ssh-add ~/.ssh/id_rsa
su username -c "eval $(ssh-agent -s)" && ssh-add ~/.ssh/id_rsa
su username -c "eval $(ssh-agent -s)" && "ssh-add ~/.ssh/id_rsa"

It seems like the first command run successfully but the second either response with Permission denied message (means it run with the current user) or cannot connect to the authentication agent (means it probably created a new session for the second command).

Error messages:

Could not open a connection to your authentication agent.
Error connecting to agent: Permission denied

If I run them separately in order, it works:///

The purpose is to create a bash script with these commands with variables, something like this:

folder=/home/q12
username=q12

su $username -c "{ eval $(ssh-agent -s) }; ssh-add $folder/.ssh/id_rsa"

Because of the variables I can not quote the whole command because it will be sensitive to ";" and "&&".

Can anyone help me with this? Thank you!

CodePudding user response:

You need single quotes. Otherwise the command substitution is evaluated in the current context.

su username -c 'eval "$(ssh-agent -s)"; ssh-add ~/.ssh/id_rsa'

Edit:

To get conditional execution of ssh-add, you can do:

su username -c 'script=$(ssh-agent -s) || exit 1; eval "$script"; ssh-add ~/.ssh/id_rsa'
# or
su username -c 'set -e; script=$(ssh-agent -s); eval "$script"; ssh-add ~/.ssh/id_rsa'

The argument in su -c STRING is a command string, similar to bash -c STRING. We can also nest double quotes inside single quotes.

CodePudding user response:

The first of your tries is closest, but inside double-quotes things like $(ssh-agent -s) get evaluated by your shell before they're passed to su as part of an argument. Net result: the ssh agent is running under the current user, so the other user can't use it.

You need to delay evaluation until the other-user shell. Using single-quotes instead of double would do this, but in the actual command you have $folder, which you clearly want evaluated by your shell (it won't be defined in the other-user shell), so you don't want to delay evaluation of that. The simplest way to do this is to escape the $ that you want to delay evaluation of (your shell will remove the escape, so the other-user shell will see & evaluate it):

su "$username" -c "{ eval \$(ssh-agent -s) }; ssh-add $folder/.ssh/id_rsa"
#                         ^ Note the escape

(BTW, I also added double-quotes around the username, as that's generally-good scripting hygiene. Quoting $folder is more complicated, and shouldn't be necessary as long as it doesn't contain any weird characters, so I skipped it.)

Another option is to single-quote part of the command and double-quote another part (mixed quoting looks weird, but is perfectly legal in shell syntax):

    su "$username" -c '{ eval $(ssh-agent -s) };'" ssh-add $folder/.ssh/id_rsa"
#                     ^   single-quoted part    ^^    double-quoted part      ^

The reason the rest of your attempts didn't work is that the delimiter between the commands (; or &&) wasn't in the quoted string, and hence was treated as a delimiter by your shell, so the second command was run under your user ID rather than as part of the su command.

  • Related