Bắt ssh để thực thi một lệnh trong nền trên máy đích


304

Đây là câu hỏi tiếp theo cho Làm thế nào để bạn sử dụng ssh trong tập lệnh shell? câu hỏi Nếu tôi muốn thực thi một lệnh trên máy từ xa chạy trong nền trên máy đó, làm cách nào để tôi nhận được lệnh ssh? Khi tôi cố gắng chỉ bao gồm ký hiệu (&) ở cuối lệnh, nó sẽ bị treo. Hình thức chính xác của lệnh trông như thế này:

ssh user@target "cd /some/directory; program-to-execute &"

Có ý kiến ​​gì không? Một điều cần lưu ý là đăng nhập vào máy đích luôn tạo ra một biểu ngữ văn bản và tôi có các khóa SSH được thiết lập để không cần mật khẩu.

Câu trả lời:


315

Tôi đã gặp vấn đề này trong một chương trình tôi đã viết cách đây một năm - hóa ra câu trả lời khá phức tạp. Bạn sẽ cần sử dụng nohup cũng như chuyển hướng đầu ra, như được giải thích trong tài liệu wikipedia trên nohup , được sao chép ở đây để thuận tiện cho bạn.

Ví dụ, các công việc nền không có ích là hữu ích khi đăng nhập qua SSH, vì các công việc được nền có thể khiến shell bị treo khi đăng xuất do điều kiện cuộc đua [2]. Vấn đề này cũng có thể được khắc phục bằng cách chuyển hướng cả ba luồng I / O:

nohup myprogram > foo.out 2> foo.err < /dev/null &

1
Những tập tin được tạo ra trong thư mục hiện tại. Vì vậy, giới hạn là dung lượng trống trên phân vùng. Tất nhiên bạn cũng có thể chuyển hướng đến /dev/null.
Frank Kuster

2
Bất kỳ ý tưởng về nền tảng quá trình sau khi nó kết thúc yêu cầu nhắc nhở? (giống như một gpg --decrypt đã hoàn thành yêu cầu mật khẩu)
isaaclw

Cố gắng bắt đầu một nhân viên phục hồi trong nền bằng cách sử dụng nohup, nhưng nó không hoạt động .. :(
Trẻ sơ sinh

1
Bạn có thể vui lòng giải thích < /dev/nullnghĩa là gì? Cảm ơn.
Qian Chen

1
Cũng từ bài viết trên wikipedia trên nohup: "Cũng lưu ý rằng phiên SSH đóng không phải lúc nào cũng gửi tín hiệu HUP đến các quy trình tùy thuộc. Trong số những người khác, điều này phụ thuộc vào việc thiết bị đầu cuối giả có được phân bổ hay không." Vì vậy, trong khi hoàn toàn không phải lúc nào cũng cần thiết, bạn vẫn lâu dài với nó hơn là không có.
Jax

254

Đây là cách sạch nhất để làm điều đó với tôi: -

ssh -n -f user@host "sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'"

Điều duy nhất chạy sau đây là lệnh thực tế trên máy từ xa


7
-nkhông cần thiết như -fngụ ý-n
blissini

6
ssh -fđể lại quá trình ssh kết nối, chỉ cần nền. Các giải pháp / dev / null cho phép ssh ngắt kết nối nhanh chóng, có thể tốt hơn.
Beni Cherniavsky-Paskin

Giải pháp này cũng hoạt động để gửi các lệnh qua ssh đến NAS Syonology
Stefan F

Tôi cần kết quả của "ls -l" để hiển thị trên điều khiển từ xa, lệnh này không thực hiện được.
Siddharth

@Siddharth Sau đó chuyển hướng đến một số tệp có tên chứ không phải / dev / null.
sherrellbc

29

Chuyển hướng fd

Đầu ra cần được chuyển hướng theo &>/dev/nullđó chuyển hướng cả stderr và stdout thành / dev / null và là từ đồng nghĩa của >/dev/null 2>/dev/nullhoặc >/dev/null 2>&1.

Parantheses

Cách tốt nhất là sử dụng sh -c '( ( command ) & )'lệnh ở đâu là bất cứ điều gì.

ssh askapache 'sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Vỏ Nohup

Bạn cũng có thể sử dụng nohup trực tiếp để khởi chạy shell:

ssh askapache 'nohup sh -c "( ( chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Khởi động tốt đẹp

Một mẹo khác là sử dụng tốt để khởi chạy lệnh / shell:

ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

8
Tôi biết đây là một câu trả lời rất cũ của bạn, nhưng bạn có thể thêm một số nhận xét về lý do tại sao cách viết ngoặc đơn là cách tốt nhất, thêm (nếu có) sự khác biệt thêm vào nohuplàm gì, và tại sao và khi nào bạn sẽ sử dụng nice? Tôi nghĩ rằng sẽ thêm rất nhiều vào câu trả lời này.
Bác sĩ K

Có lẽ để trả lời một phần điều này: Với nohup, bạn không cần phải thêm & vào lệnh để được chạy.
Cadoiz

21

Nếu bạn không / không thể giữ kết nối mở, bạn có thể sử dụng màn hình , nếu bạn có quyền cài đặt nó.

user@localhost $ screen -t remote-command
user@localhost $ ssh user@target # now inside of a screen session
user@remotehost $ cd /some/directory; program-to-execute &

Để tách phiên màn hình: ctrl-a d

Để liệt kê các phiên màn hình:

screen -ls

Để gắn lại một phiên:

screen -d -r remote-command

Lưu ý rằng màn hình cũng có thể tạo nhiều shell trong mỗi phiên. Một hiệu ứng tương tự có thể đạt được với tmux .

user@localhost $ tmux
user@localhost $ ssh user@target # now inside of a tmux session
user@remotehost $ cd /some/directory; program-to-execute &

Để tách phiên tmux: ctrl-b d

Để liệt kê các phiên màn hình:

tmux list-sessions

Để gắn lại một phiên:

tmux attach <session number>

Khóa điều khiển tmux mặc định, ' ctrl-b', hơi khó sử dụng nhưng có một số ví dụ cấu hình tmux đi kèm với tmux mà bạn có thể thử.


3
Làm thế nào một người sẽ sử dụng screencho điều này?
Quamis

18

Tôi chỉ muốn đưa ra một ví dụ hoạt động mà bạn có thể cắt và dán:

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""

Rất hữu ích. Cảm ơn.
Michael Martinez

8

Cách nhanh nhất và dễ nhất là sử dụng lệnh 'at':

người dùng ssh @ target "lúc này -f /home/foo.sh"


2
Đây sẽ là một giải pháp chung tuyệt vời nếu atđược chấp nhận đối số dòng lệnh sau thời gian và không chỉ từ một tệp.
Tyler Collier

3
Bạn có thể mô phỏng một tệp với <<< like in: ssh user @ target "ngay bây giờ -f <<< 'my_comnads'"
Nico

6

Tôi nghĩ bạn sẽ phải kết hợp một vài trong số những câu trả lời này để có được điều bạn muốn. Nếu bạn sử dụng nohup kết hợp với dấu chấm phẩy và gói toàn bộ trong ngoặc kép, thì bạn nhận được:

ssh user@target "cd /some/directory; nohup myprogram > foo.out 2> foo.err < /dev/null"

mà dường như làm việc cho tôi Với nohup, bạn không cần phải thêm & vào lệnh để được chạy. Ngoài ra, nếu bạn không cần đọc bất kỳ đầu ra nào của lệnh, bạn có thể sử dụng

ssh user@target "cd /some/directory; nohup myprogram > /dev/null 2>&1"

để chuyển hướng tất cả đầu ra thành / dev / null.


5

Điều này làm việc cho tôi có thể nhiều lần:

ssh -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & " 

2

Bạn có thể làm điều đó như thế này ...

sudo /home/script.sh -opt1 > /tmp/script.out &

Hoàn hảo, hoạt động với phiên SSH PuTTY. Tôi có thể thoát và tập lệnh tiếp tục trên máy. Cảm ơn bạn.
Satria

1

Trên thực tế, bất cứ khi nào tôi cần chạy một lệnh trên một máy từ xa phức tạp, tôi muốn đặt lệnh trong một tập lệnh trên máy đích và chỉ chạy tập lệnh đó bằng ssh.

Ví dụ:

# simple_script.sh (located on remote server)

#!/bin/bash

cat /var/log/messages | grep <some value> | awk -F " " '{print $8}'

Và sau đó tôi chỉ chạy lệnh này trên máy nguồn:

ssh user@ip "/path/to/simple_script.sh"

0

Tôi đã cố gắng làm điều tương tự, nhưng với sự phức tạp thêm vào mà tôi đã cố gắng làm điều đó từ Java. Vì vậy, trên một máy chạy java, tôi đã cố chạy một đoạn script trên máy khác, ở chế độ nền (không có tiếng ồn).

Từ dòng lệnh, đây là những gì đã hoạt động: (bạn có thể không cần "-i keyFile" nếu bạn không cần nó để ssh cho máy chủ)

ssh -i keyFile user@host bash -c "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\""

Lưu ý rằng đối với dòng lệnh của tôi, có một đối số sau "-c", tất cả nằm trong dấu ngoặc kép. Nhưng để nó hoạt động ở đầu bên kia, nó vẫn cần các trích dẫn, vì vậy tôi đã phải đặt các trích dẫn thoát trong đó.

Từ java, đây là những gì đã làm việc:

ProcessBuilder b = new ProcessBuilder("ssh", "-i", "keyFile", "bash", "-c",
 "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\"");
Process process = b.start();
// then read from process.getInputStream() and close it.

Phải mất một chút thử nghiệm và lỗi để làm việc này, nhưng có vẻ như bây giờ nó hoạt động tốt.


0

Nó xuất hiện khá thuận tiện cho tôi để có một phiên tmux từ xa bằng cách sử dụng tmux new -d <shell cmd>cú pháp như thế này:

ssh someone@elsewhere 'tmux new -d sleep 600'

Điều này sẽ khởi chạy phiên mới trên elsewheremáy chủ và lệnh ssh trên máy cục bộ sẽ trở lại shell gần như ngay lập tức. Sau đó, bạn có thể ssh đến máy chủ từ xa và tmux attachđến phiên đó. Lưu ý rằng không có gì về tmux cục bộ đang chạy, chỉ có điều khiển từ xa!

Ngoài ra, nếu bạn muốn phiên của bạn tiếp tục sau khi hoàn thành công việc, chỉ cần thêm trình khởi chạy shell sau lệnh của bạn, nhưng đừng quên kèm theo dấu ngoặc kép:

ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'

0
YOUR-COMMAND &> YOUR-LOG.log &    

Điều này sẽ chạy lệnh và gán một id quá trình mà bạn có thể chỉ cần theo đuôi -f CỦA BẠN-LOG.log để xem kết quả được ghi cho nó khi chúng xảy ra. bạn có thể đăng xuất bất cứ lúc nào và quá trình sẽ tiếp tục


0

Bạn có thể làm điều này mà không cần nohup:

ssh user@host 'myprogram >out.log 2>err.log &'

-2

Tôi nghĩ rằng đây là những gì bạn cần: Đầu tiên bạn cần cài đặt sshpasstrên máy của mình. sau đó bạn có thể viết kịch bản của riêng bạn:

while read pass port user ip; do
sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE

-3

Đầu tiên làm theo thủ tục này:

Đăng nhập vào A với tư cách là người dùng a và tạo một cặp khóa xác thực. Không nhập cụm mật khẩu:

a@A:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/a/.ssh/id_rsa): 
Created directory '/home/a/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/a/.ssh/id_rsa.
Your public key has been saved in /home/a/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 a@A

Bây giờ sử dụng ssh để tạo một thư mục ~ / .ssh là người dùng b trên B. (Thư mục có thể đã tồn tại, điều này là tốt):

a@A:~> ssh b@B mkdir -p .ssh
b@B's password: 

Cuối cùng, thêm khóa công khai mới của b vào B @ B: .ssh / ủy quyền và nhập mật khẩu của b lần cuối:

a@A:~> cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys'
b@B's password: 

Từ giờ bạn có thể đăng nhập vào B là b từ A dưới dạng không có mật khẩu:

a@A:~> ssh b@B

sau đó nó sẽ hoạt động mà không cần nhập mật khẩu

ssh b @ B "cd / some / thư mục; chương trình thực thi &"


1
Câu hỏi nói rằng dagorym đã thiết lập các khóa để không yêu cầu mật khẩu, nhưng nó vẫn bị treo
Max Nanasy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.