Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connect not running ~/.bash_profile #649

Open
krankydonkey opened this issue Apr 10, 2024 · 11 comments
Open

connect not running ~/.bash_profile #649

krankydonkey opened this issue Apr 10, 2024 · 11 comments

Comments

@krankydonkey
Copy link

krankydonkey commented Apr 10, 2024

Running
async with asyncssh.connect(ip, username=uname, password=passwd, known_hosts=None) as conn
Within a podman container will log in as the given user, but does not run the ~/.bash_profile file.

Running
ssh uname@ip and giving the password at the prompt works as expected.

Any ideas why this would be the case?

@ronf
Copy link
Owner

ronf commented Apr 10, 2024

Did you actually open a session after opening the connection? You need to call something like conn.run() after opening a connection to actually run a command (or a shell), and only then will the remote system run something like ~/.bash_profile. See the example at https://asyncssh.readthedocs.io/en/latest/#simple-client.

@krankydonkey
Copy link
Author

krankydonkey commented Apr 10, 2024 via email

@ronf
Copy link
Owner

ronf commented Apr 10, 2024

Actually, if you are trying to run a command, I'm not sure that I'd expect .bash_profile to run. Doesn't that run only on login shells?

@ronf
Copy link
Owner

ronf commented Apr 13, 2024

I've confirmed that running 'ssh' with a command to execute will not run what's in .bash_profile. However, running 'ssh' and requesting an interactive shell WILL run .bash_profile. This is standard bash behavior, and has nothing to do with AsyncSSH.

@xjie0626
Copy link

@ronf Hello ,Before executing a command, I always execute source~/. bash_profile, but some hosts may print out information that I don't want to obtain. However, I cannot mask it by executing source~/. bash_profile>/dev/null 2>&1. Why is this? I just want to load the user's environment variables, or is there any other better way?

thanks

@ronf
Copy link
Owner

ronf commented Jun 14, 2024

I just did a test here, and redirection in a "source" command works just fine for me.

How are you running the command in AsyncSSH? Are you providing it as a command argument, or are you opening up an interactive shell (with no value for command) and then writing the "source" command to stdin on the resulting channel?

You can't really use command in this case, since that runs each command you provide in a separate session, with its own bash shell. So, even if you did set environment variables from ~/.bash_profile, they wouldn't be present when you run the command after that if you do so in a separate session.

I also wonder if maybe it is running ~/.bash_profile for you in some cases, and that's the output you're seeing rather than from when you try to source it.

I've also seen logic in ~/.bash_profile which can try and test whether the shell in interactive or not, or whether it is a login shell, and that can have an impact on what parts of bash_profile get run. Do you have examples of how you are starting a shell?

@xjie0626
Copy link

Thank you for your reply
this is my code

async def run_command(self, command, timeout=30):
    if self.conn is not None:
        try:
            new_command = "source ~/.bash_profile >/dev/null 2>&1;\n"
            new_command += "source /etc/profile >/dev/null 2>&1;\n"
            new_command += command
            print(new_command)
            results = await self.conn.run(
                new_command,
                timeout=timeout,
            )
            print(results) 
            stdout = results.stdout
            stderr = results.stderr
            status = results.exit_status
            data = stdout if stdout else stderr

If I execute "source~/. bash_profile", I set it to output the message "hello"
I execute this command through AsyncSSH and it will take effect, but I don't want to output information on the screen, so I use the command source~/. bash_profile>/dev/null 2>&1; (On Linux, it does not output any information), but AsyncSSH still prints the results. For example, if my command is "hostname", it will print hello first, and then print the host name. It seems that the command ">/dev/null 2>&1" to block information is invalid, or is there any other way for AsyncSSH to block it

thanks

@xjie0626
Copy link

I retested later, What I said before was not very accurate. If "echo hello" is in the ”.bash_profile“ file, it can be blocked, but .bash_profile will execute ".~/.bashrc", If "echo hello" is in the .bashrc file, it cannot be blocked

@ronf
Copy link
Owner

ronf commented Jun 18, 2024

I tested something similar to your example here, and the redirection seems to be working ok. However, it looks like bashrc is being run automatically by bash on the remote systems, even when you are running an explicit command. This is not an AsyncSSH issue -- I get the exact same result when I use OpenSSH as a client. So, while you may be blocking the output in the explicit instance of .bashrc you are telling it to run, the bash shell you are starting up on the server is already running .bashrc, without any redirection.

Note that bash_profile is not run automatically here, as the shell is not considered a login shell. If you run that explicitly and it then chooses to run .bashrc, though, .bashrc may be getting run a total of three times, two with redirection but one without.

This doesn't seem to happen with zsh. It will run zshrc on interactive shells, but not when running a command like this. The bash man page seems to claim the behavior should be the same for bash, but in my tests that was not what I saw.

If you take out the command to run .bashrc explicitly here, you should be able to confirm if bash on the remote system is still running .bashrc on its own. Perhaps you could put in a check there via something like an environment variable that tells it not to write any output when you are coming in over SSH from this script.

@xjie0626
Copy link

Perhaps I want to achieve the same effect as the Linux operating system, because I see that executing ssh 192.168.1.70 source/home/jxgmapp/. bash_profile 1>/dev/null 2>&1 can also be masked (regardless of whether. bash_profile calls other scripts with output), but the probability of this situation occurring is not high and can be targeted.
Thank you very much for your answer

@ronf
Copy link
Owner

ronf commented Jun 25, 2024

If you know the remote shell will always be bash, you should be able to know which init files will be run automatically when starting a remote shell. More specifically from what I can see, opening an interactive shell in SSH will run ".bash_profile" (essentially treating the new SSH connection as a login shell), but running a specific command via SSH will run ".bashrc". I don't think it'll ever run both, but you would be free to put something in ".bash_profile" that ran ".bashrc" if you wanted that.

Unfortunately, these files will always be run with no redirection of output. So, if you want that, you'll have to do that redirection from INSIDE the ".bash_profile" and/or ".bashrc". In general, I would avoid trying to run these files yourself, since that'll just cause one of them to run multiple times.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants