รับ ssh เพื่อรันคำสั่งในพื้นหลังบนเครื่องเป้าหมาย


304

นี่เป็นคำถามต่อไปนี้คุณจะใช้ ssh ในเชลล์สคริปต์ได้อย่างไร คำถาม. หากฉันต้องการรันคำสั่งบนเครื่องรีโมตที่รันในพื้นหลังบนเครื่องนั้นฉันจะเรียกคำสั่ง ssh กลับมาได้อย่างไร? เมื่อฉันพยายามที่จะรวมเครื่องหมายและ (&) ที่ส่วนท้ายของคำสั่งมันก็แฮงค์ รูปแบบที่แน่นอนของคำสั่งมีลักษณะดังนี้:

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

ความคิดใด ๆ สิ่งหนึ่งที่ควรทราบคือการเข้าสู่ระบบไปยังเครื่องเป้าหมายจะสร้างแบนเนอร์ข้อความเสมอและฉันมีการตั้งค่าคีย์SSHดังนั้นจึงไม่จำเป็นต้องใช้รหัสผ่าน

คำตอบ:


315

ฉันมีปัญหานี้ในโปรแกรมที่ฉันเขียนเมื่อปีที่แล้ว - คำตอบนั้นค่อนข้างซับซ้อน คุณจะต้องใช้ nohup เช่นเดียวกับการเปลี่ยนเส้นทางออกตามที่อธิบายไว้ในวิกิพีเดีย artcle ในnohupคัดลอกมาที่นี่เพื่อความสะดวกของคุณ

ยกตัวอย่างเช่นงานที่ไม่มีพื้นหลังเป็นประโยชน์เมื่อเข้าสู่ระบบผ่าน SSH เนื่องจากงานที่ทำพื้นหลังอาจทำให้เชลล์หยุดทำงานเมื่อออกจากระบบเนื่องจากสภาพการแข่งขัน [2] ปัญหานี้สามารถแก้ไขได้ด้วยการเปลี่ยนเส้นทางสตรีม I / O ทั้งสาม:

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

1
ไฟล์เหล่านั้นถูกสร้างขึ้นในไดเรกทอรีปัจจุบัน ดังนั้นข้อ จำกัด คือจำนวนพื้นที่ว่างบนพาร์ติชัน /dev/nullแน่นอนคุณยังสามารถเปลี่ยนเส้นทางไปยัง
Frank Kusters

2
มีแนวคิดใดบ้างที่ทำให้พื้นหลังของกระบวนการหลังจากเสร็จสิ้นการถามพร้อมท์ (เช่น gpg --decrypt ที่ขอสำเร็จรูปสำหรับรหัสผ่าน)
isaaclw

พยายามเริ่มงาน resque ในพื้นหลังโดยใช้ nohup แต่มันใช้งานไม่ได้ .. :(
ทารก Dev

1
คุณช่วยอธิบายความ< /dev/nullหมายของสิ่งนั้นได้ไหม ขอบคุณ
Qian Chen

1
และจากบทความวิกิพีเดียใน nohup: "นอกจากนี้โปรดทราบว่าการปิดเซสชัน SSH นั้นไม่ได้ส่งสัญญาณ HUP ไปสู่กระบวนการที่ขึ้นอยู่กับคนอื่น ๆ เสมอไปนอกจากนี้ยังขึ้นอยู่กับว่ามีการจัดสรรเทอร์มินัลหลอกหรือไม่" ดังนั้นแม้ว่า nohup อาจไม่จำเป็นเสมอไป แต่คุณจะต้องใช้เวลานานกว่า
Jax

254

นี่เป็นวิธีที่สะอาดที่สุดสำหรับฉัน: -

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

สิ่งเดียวที่ทำงานหลังจากนี้คือคำสั่งจริงบนเครื่องระยะไกล


7
-nไม่จำเป็นต้องเป็น-fนัย-n
blissini

6
ssh -fออกจากการเชื่อมต่อกระบวนการ ssh เพียงแค่มีพื้นหลัง โซลูชัน / dev / null อนุญาตให้ ssh ตัดการเชื่อมต่ออย่างรวดเร็วซึ่งอาจเป็นที่ต้องการ
Beni Cherniavsky-Paskin

วิธีนี้ใช้ได้กับการส่งคำสั่งผ่าน ssh ไปยัง Syonology NAS
Stefan F

ฉันต้องการผลลัพธ์ของ "ls -l" เพื่อแสดงบนรีโมตของฉันคำสั่งนี้ไม่ได้ทำ
Siddharth

@Siddharth จากนั้นเปลี่ยนเส้นทางไปยังไฟล์ที่กำหนดชื่อไว้แทนที่จะเป็น / dev / null
sherrellbc

29

เปลี่ยนเส้นทางของ fd

ความต้องการส่งออกไปยังถูกเปลี่ยนเส้นทางไปด้วย&>/dev/nullซึ่งทั้งเปลี่ยนเส้นทาง stderr stdout และ / dev / โมฆะและเป็นไวพจน์ของหรือ>/dev/null 2>/dev/null>/dev/null 2>&1

วงเล็บ

วิธีที่ดีที่สุดคือใช้sh -c '( ( command ) & )'คำสั่ง where คืออะไร

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

Nohup Shell

คุณยังสามารถใช้ nohup โดยตรงเพื่อเปิดเปลือก:

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

การเปิดตัวที่ดี

เคล็ดลับอีกอย่างคือการใช้ nice เพื่อเรียกใช้ command / shell:

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

8
ฉันรู้ว่านี่เป็นคำตอบที่เก่ามากของคุณ แต่คุณสามารถเพิ่มความคิดเห็นเกี่ยวกับสาเหตุที่วงเล็บเป็นวิธีที่ดีที่สุดการเพิ่มความแตกต่าง (ถ้ามี) nohupทำให้เกิดอะไรและทำไมและเมื่อใดที่คุณจะใช้nice? ฉันคิดว่ามันจะเพิ่มคำตอบนี้มาก
ดร. เค

อาจตอบได้บางส่วนด้วย nohup คุณไม่จำเป็นต้องผนวก & ไปยังคำสั่งเพื่อให้ทำงาน
Cadoiz

21

หากคุณไม่สามารถเปิดการเชื่อมต่อได้คุณไม่สามารถใช้หน้าจอได้หากคุณมีสิทธิ์ติดตั้ง

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 &

วิธีแยกเซสชั่นหน้าจอ: ctrl-a d

ในการแสดงรายการเซสชันหน้าจอ:

screen -ls

หากต้องการแนบเซสชันอีกครั้ง:

screen -d -r remote-command

โปรดทราบว่าหน้าจอสามารถสร้างเชลล์ได้หลายตัวในแต่ละเซสชัน ผลที่คล้ายกันสามารถทำได้ด้วยtmux

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

หากต้องการแยกเซสชัน tmux: ctrl-b d

ในการแสดงรายการเซสชันหน้าจอ:

tmux list-sessions

หากต้องการแนบเซสชันอีกครั้ง:

tmux attach <session number>

คีย์ควบคุม tmux เริ่มต้น ' ctrl-b' ค่อนข้างใช้งานยาก แต่มีตัวอย่างหลายตัวอย่างของ tmux ที่มาพร้อมกับ tmux ที่คุณสามารถลองได้


3
คนเราจะใช้screenสิ่งนี้อย่างไร?
Quamis

18

ฉันแค่ต้องการแสดงตัวอย่างการทำงานที่คุณสามารถตัดและวาง:

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

มีประโยชน์มาก ขอขอบคุณ
Michael Martinez

8

วิธีที่เร็วและง่ายที่สุดคือใช้คำสั่ง 'at':

ssh user @ target "ที่ตอนนี้ -f /home/foo.sh"


2
นี่จะเป็นวิธีแก้ปัญหาทั่วไปที่ยอดเยี่ยมหากatยอมรับอาร์กิวเมนต์บรรทัดคำสั่งหลังจากเวลานั้นและไม่เพียง แต่มาจากไฟล์
Tyler Collier

3
คุณสามารถจำลองไฟล์ที่มี <<< เหมือนใน: ssh user @ target "at now -f <<< 'my_comnads'"
Nico

6

ฉันคิดว่าคุณจะต้องรวมสองคำตอบเหล่านี้เพื่อให้ได้สิ่งที่คุณต้องการ หากคุณใช้ nohup ร่วมกับเครื่องหมายอัฒภาคและห่อทุกสิ่งด้วยเครื่องหมายคำพูดคุณจะได้รับ:

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

ซึ่งดูเหมือนจะทำงานให้ฉัน ด้วย nohup คุณไม่จำเป็นต้องผนวก & ไปยังคำสั่งเพื่อให้ทำงาน นอกจากนี้หากคุณไม่จำเป็นต้องอ่านเอาต์พุตใด ๆ ของคำสั่งคุณสามารถใช้

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

เพื่อเปลี่ยนเส้นทางเอาต์พุตทั้งหมดเป็น / dev / null


5

สิ่งนี้ได้ผลกับฉันหลายครั้ง:

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

2

คุณสามารถทำได้เช่นนี้ ...

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

สมบูรณ์แบบใช้ได้กับเซสชัน PuTTY SSH ฉันสามารถออกและสคริปต์ดำเนินการต่อในเครื่อง ขอบคุณ.
Satria

1

ที่จริงแล้วเมื่อใดก็ตามที่ฉันต้องการเรียกใช้คำสั่งบนเครื่องระยะไกลที่ซับซ้อนฉันชอบที่จะวางคำสั่งในสคริปต์บนเครื่องปลายทางและเพียงเรียกใช้สคริปต์นั้นโดยใช้ ssh

ตัวอย่างเช่น:

# simple_script.sh (located on remote server)

#!/bin/bash

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

จากนั้นฉันก็รันคำสั่งนี้บนเครื่องต้นทาง:

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

0

ฉันพยายามทำสิ่งเดียวกัน แต่ด้วยความซับซ้อนที่เพิ่มขึ้นที่ฉันพยายามทำจาก Java ดังนั้นในเครื่องหนึ่งที่ใช้งานจาวาฉันก็พยายามเรียกใช้สคริปต์บนเครื่องอื่นในแบบแบ็คกราวน์

จากบรรทัดคำสั่งนี่คือสิ่งที่ใช้งานได้: (คุณอาจไม่ต้องการ "-i keyFile" หากคุณไม่ต้องการให้ ssh ไปยังโฮสต์)

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

โปรดทราบว่าในบรรทัดคำสั่งของฉันมีหนึ่งอาร์กิวเมนต์หลังจาก "-c" ซึ่งทั้งหมดอยู่ในเครื่องหมายคำพูด แต่สำหรับการทำงานในส่วนอื่น ๆ มันยังคงต้องการใบเสนอราคาดังนั้นฉันต้องใส่เครื่องหมายอัญประกาศที่อยู่ภายใน

จาก java นี่คือสิ่งที่ใช้งานได้:

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.

การทดลองใช้ & ข้อผิดพลาดเล็กน้อยเพื่อให้ได้งานนี้ แต่ดูเหมือนว่าจะทำงานได้ดีในขณะนี้


0

มันค่อนข้างสะดวกสำหรับฉันที่จะมีเซสชั่น tmux ระยะไกลโดยใช้tmux new -d <shell cmd>ไวยากรณ์เช่นนี้

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

นี่จะเป็นการเปิดเซสชันใหม่บนelsewhereโฮสต์และคำสั่ง ssh บนเครื่องโลคัลจะกลับสู่เชลล์เกือบจะในทันที จากนั้นคุณสามารถ ssh ไปยังรีโมตโฮสต์และtmux attachเซสชันนั้น โปรดทราบว่าไม่มีอะไรเกี่ยวกับ tmux ท้องถิ่นที่ทำงานเพียงระยะไกล!

นอกจากนี้หากคุณต้องการให้เซสชันของคุณคงอยู่หลังจากงานเสร็จเพียงเพิ่มตัวเรียกใช้เชลล์หลังจากคำสั่งของคุณ แต่อย่าลืมใส่เครื่องหมายคำพูด:

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

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

สิ่งนี้ควรรันคำสั่งและกำหนดรหัสกระบวนการที่คุณสามารถ tail -f YOUR-LOG.log ของคุณเพื่อดูผลลัพธ์ที่เขียนขึ้นเมื่อมันเกิดขึ้น คุณสามารถออกจากระบบได้ตลอดเวลาและดำเนินการต่อ



-2

ฉันคิดว่านี่คือสิ่งที่คุณต้องการ: ตอนแรกคุณต้องติดตั้งsshpassบนเครื่องของคุณ จากนั้นคุณสามารถเขียนสคริปต์ของคุณเอง:

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

ทำตามขั้นตอนนี้ก่อน:

เข้าสู่ระบบในฐานะผู้ใช้กและสร้างคู่ของคีย์การรับรอง อย่าป้อนข้อความรหัสผ่าน:

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

ตอนนี้ใช้ ssh เพื่อสร้างไดเรกทอรี ~ / .ssh เป็นผู้ใช้ขใน B (ไดเรกทอรีอาจมีอยู่แล้วซึ่งเป็นเรื่องปกติ):

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

ในที่สุดผนวก a สาธารณะคีย์ใหม่เพื่อ b @ B: .ssh / authorized_keys และป้อนรหัสผ่านของ b เป็นครั้งสุดท้าย:

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

จากนี้ไปคุณสามารถเข้าสู่ B เป็น b จาก A โดยไม่ต้องใช้รหัสผ่าน:

a@A:~> ssh b@B

จากนั้นสิ่งนี้จะทำงานโดยไม่ต้องป้อนรหัสผ่าน

ssh b @ B "cd / some / directory; program-to-execute &"


1
คำถามบอกว่า dagorym ตั้งค่าคีย์ไว้แล้วว่าไม่ต้องการรหัสผ่าน แต่มันยังค้างอยู่
Max Nanasy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.