How to use SSH to run a local shell script on a remote machine?

前端 未结 17 1581
南笙
南笙 2020-11-21 22:33

I have to run a local shell script (windows/Linux) on a remote machine.

I have SSH configured on both machine A and B. My script is on machine A which will run some o

相关标签:
17条回答
  • 2020-11-21 23:02

    This is an extension to YarekT's answer to combine inline remote commands with passing ENV variables from the local machine to the remote host so you can parameterize your scripts on the remote side:

    ssh user@host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'
      # commands to run on remote host
      echo $ARG1 $ARG2
    ENDSSH
    

    I found this exceptionally helpful by keeping it all in one script so it's very readable and maintainable.

    Why this works. ssh supports the following syntax:

    ssh user@host remote_command

    In bash we can specify environment variables to define prior to running a command on a single line like so:

    ENV_VAR_1='value1' ENV_VAR_2='value2' bash -c 'echo $ENV_VAR_1 $ENV_VAR_2'

    That makes it easy to define variables prior to running a command. In this case echo is our command we're running. Everything before echo defines environment variables.

    So we combine those two features and YarekT's answer to get:

    ssh user@host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'...

    In this case we are setting ARG1 and ARG2 to local values. Sending everything after user@host as the remote_command. When the remote machine executes the command ARG1 and ARG2 are set the local values, thanks to local command line evaluation, which defines environment variables on the remote server, then executes the bash -s command using those variables. Voila.

    0 讨论(0)
  • 2020-11-21 23:03

    I use this one to run a shell script on a remote machine (tested on /bin/bash):

    ssh deploy@host . /home/deploy/path/to/script.sh
    
    0 讨论(0)
  • 2020-11-21 23:03

    The answer here (https://stackoverflow.com/a/2732991/4752883) works great if you're trying to run a script on a remote linux machine using plink or ssh. It will work if the script has multiple lines on linux.

    **However, if you are trying to run a batch script located on a local linux/windows machine and your remote machine is Windows, and it consists of multiple lines using **

    plink root@MachineB -m local_script.bat

    wont work.

    Only the first line of the script will be executed. This is probably a limitation of plink.

    Solution 1:

    To run a multiline batch script (especially if it's relatively simple, consisting of a few lines):

    If your original batch script is as follows

    cd C:\Users\ipython_user\Desktop 
    python filename.py
    

    you can combine the lines together using the "&&" separator as follows in your local_script.bat file: https://stackoverflow.com/a/8055390/4752883:

    cd C:\Users\ipython_user\Desktop && python filename.py
    

    After this change, you can then run the script as pointed out here by @JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883 with:

    `plink root@MachineB -m local_script.bat`
    

    Solution 2:

    If your batch script is relatively complicated, it may be better to use a batch script which encapsulates the plink command as well as follows as pointed out here by @Martin https://stackoverflow.com/a/32196999/4752883:

    rem Open tunnel in the background
    start plink.exe -ssh [username]@[hostname] -L 3307:127.0.0.1:3306 -i "[SSH
    key]" -N
    
    rem Wait a second to let Plink establish the tunnel 
    timeout /t 1
    
    rem Run the task using the tunnel
    "C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R
    
    rem Kill the tunnel
    taskkill /im plink.exe
    
    0 讨论(0)
  • 2020-11-21 23:05

    Also, don't forget to escape variables if you want to pick them up from the destination host.

    This has caught me out in the past.

    For example:

    user@host> ssh user2@host2 "echo \$HOME"
    

    prints out /home/user2

    while

    user@host> ssh user2@host2 "echo $HOME"
    

    prints out /home/user

    Another example:

    user@host> ssh user2@host2 "echo hello world | awk '{print \$1}'"
    

    prints out "hello" correctly.

    0 讨论(0)
  • 2020-11-21 23:06

    This is an old question, and Jason's answer works fine, but I would like to add this:

    ssh user@host <<'ENDSSH'
    #commands to run on remote host
    ENDSSH
    

    This can also be used with su and commands which require user input. (note the ' escaped heredoc)

    Edit: Since this answer keeps getting bits of traffic, i would add even more info to this wonderful use of heredoc:

    You can nest commands with this syntax, and thats the only way nesting seems to work (in a sane way)

    ssh user@host <<'ENDSSH'
    #commands to run on remote host
    ssh user@host2 <<'END2'
    # Another bunch of commands on another host
    wall <<'ENDWALL'
    Error: Out of cheese
    ENDWALL
    ftp ftp.secureftp-test.com <<'ENDFTP'
    test
    test
    ls
    ENDFTP
    END2
    ENDSSH
    

    You can actually have a conversation with some services like telnet, ftp, etc. But remember that heredoc just sends the stdin as text, it doesn't wait for response between lines

    Edit: I just found out that you can indent the insides with tabs if you use <<-END !

    ssh user@host <<-'ENDSSH'
        #commands to run on remote host
        ssh user@host2 <<-'END2'
            # Another bunch of commands on another host
            wall <<-'ENDWALL'
                Error: Out of cheese
            ENDWALL
            ftp ftp.secureftp-test.com <<-'ENDFTP'
                test
                test
                ls
            ENDFTP
        END2
    ENDSSH
    

    (I think this should work)

    Also see http://tldp.org/LDP/abs/html/here-docs.html

    0 讨论(0)
提交回复
热议问题