คำสั่ง ssh ยังคงเกิดขึ้นในระบบอื่นโดยไม่คาดคิดหลังจาก ssh ถูกยกเลิก


11

ฉันใช้คำสั่งด้านล่างและตรวจสอบไฟล์ที่ส่งออกในระบบอื่น ๆ :

ssh $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

หากฉันฆ่าคำสั่ง ssh โดยใช้^Cหรือเพียงแค่ฆ่าเทอร์มินัลที่ฉันเข้าสู่ระบบฉันคาดว่าคำสั่งระยะไกลจะยุติเช่นกัน สิ่งนี้ไม่ได้เกิดขึ้น: /tmp/countรับตัวเลขทั้งหมด 1-5 โดยไม่คำนึงถึงและps -ejHแสดงให้เห็นว่าเชลล์และsleepลูกของมันยังคงทำงานต่อไป

นี่เป็นพฤติกรรมที่คาดหวังและมีการบันทึกไว้ที่ใดบ้างหรือไม่ ฉันจะปิดการใช้งานมันได้หรือไม่ จากการอ่านไปเรื่อย ๆ ฉันคาดว่าจะต้องเปิดใช้งานพฤติกรรมแบบนี้โดยไม่ต้องรออย่างชัดเจนไม่ใช่เพื่อให้เป็นค่าเริ่มต้น

ฉันได้ดูหน้าคู่มือสำหรับ ssh และ sshd แต่ไม่เห็นสิ่งที่ชัดเจนและ Google ชี้ให้ฉันดูคำแนะนำในการเปิดใช้งานพฤติกรรมนี้ไม่ใช่เพื่อปิด

ฉันใช้ Red Hat Enterprise Linux 6.2 พร้อมด้วยล็อกอินรูทและ bash shell บนทั้งสองระบบ

คำตอบ:


11

คำตอบของ utherบอกให้คุณจัดสรรเทอร์มินัล แต่ไม่ได้อธิบายว่าทำไม เหตุผลไม่เฉพาะเจาะจงกับ ssh มันเป็นเรื่องของการสร้างสัญญาณและการขยายพันธุ์ ฉันเชิญคุณให้อ่านอะไรเป็นสาเหตุให้มีการส่งสัญญาณต่าง ๆ สำหรับพื้นหลังเพิ่มเติม

บนรีโมตโฮสต์มีสองกระบวนการที่เกี่ยวข้อง:

  • อินสแตนซ์ของ ssh daemon ( sshd) ซึ่งกำลังถ่ายทอดอินพุตและเอาต์พุตของโปรแกรมรีโมตไปยังโลคัลเทอร์มินัล
  • เชลล์ซึ่งรันforลูปนั้น

เปลือกสามารถตายได้ตามธรรมชาติเมื่อถึงจุดสิ้นสุดของลูปหรือพบข้อผิดพลาดร้ายแรงหรือสัญญาณ คำถามคือทำไมเชลล์ถึงได้รับสัญญาณ

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

คุณสามารถผ่าน-tตัวเลือกไปยัง ssh เพื่อบอกให้เลียนแบบเทอร์มินัลทางด้านระยะไกลและเรียกใช้คำสั่งที่ระบุในเทอร์มินัลนี้ จากนั้นหากไคลเอนต์ SSH หายไปsshdปิดการเชื่อมต่อและออกจากการทำลายอาคาร เมื่ออุปกรณ์ปลายทางออกไปกระบวนการใด ๆ ที่ทำงานในนั้นได้รับSIGHUP ดังนั้นหากคุณฆ่าไคลเอ็นต์ SSH (ด้วยkillหรือปิดเทอร์มินัลที่ไคลเอ็นต์กำลังทำงานอยู่) รีโมตเชลล์คือ SIGHUPped

หากคุณผ่าน-tตัวเลือก SSH จะถ่ายทอดSIGINTด้วย หากคุณกดCtrl+ Cจากนั้นรีโมตเชลล์จะได้รับ SIGINT


ใช้-ttแทน-tถ้า ssh เองไม่มีการจัดสรร TTY SSH จะไม่ได้รับการจัดสรร TTY ถ้า SSH ได้รับ backgrounded ทันทีเมื่อภาวนาผ่านตัวเลือกเช่นหรือ-f -n
Miron V

3

ลองจัดสรร psuedo-tty ด้วยsshคำสั่งของคุณ

ssh -t $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

เมื่อคุณยกเลิกการเชื่อมต่อเซสชัน ssh กระบวนการควรยุติลง

เนื่องจากนี่เป็นแบบหลอกการเริ่มต้นเชลล์ของคุณอาจไม่ไปที่ไฟล์การกำหนดค่าต้นทางทำให้คำสั่งของคุณมีสภาพแวดล้อมที่เปลือยเปล่า คุณอาจต้องตั้งค่า.ssh/environmentไฟล์ที่กำหนดตัวแปรสภาพแวดล้อมเช่น PATH จากman 1 ssh

Additionally, ssh reads ~/.ssh/environment, and adds lines of the format 
“VARNAME=value” to the environment if the file exists and users are allowed
to change their environment.  For more information, see the 
PermitUserEnvironment option in sshd_config(5).

2

เป็นทางเลือกแทนการใช้-tตัวเลือกเพื่อsshทำให้คำสั่งรีโมตสิ้นสุดลงเมื่อsshไคลเอ็นต์ออกหรือ (ถูกฆ่า) ไพพ์ที่มีชื่อสามารถใช้เพื่อแปลง "EOF เป็น SIGHUP" เมื่อ stdin ของsshdถูกปิด (ดูBug 396 - sshd เด็กกำพร้าดำเนินการเมื่อไม่มีการจัดสรร pty )

# sample code in Bash
# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f "$TUBE"
mkfifo "$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf. "OpenSSH and non-blocking mode", 
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN "PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '%s' "$char"; done > "$TUBE"

#kill -HUP -$appPID 
kill $appPID

rm -f "$TUBE"
'

1

นี่เป็นวิธีที่ดีที่สุดที่ฉันพบว่าทำสิ่งนี้ คุณต้องการบางสิ่งในฝั่งเซิร์ฟเวอร์ที่พยายามอ่าน stdin แล้วฆ่ากลุ่มกระบวนการเมื่อล้มเหลว แต่คุณต้องการ stdin ที่ฝั่งไคลเอ็นต์ที่บล็อกจนกว่ากระบวนการฝั่งเซิร์ฟเวอร์จะเสร็จสิ้นและจะไม่ละทิ้งกระบวนการเช่น <( หลับไม่ จำกัด ) อาจ

ssh localhost "sleep 99 < <(cat; kill -INT 0)" <&1

ดูเหมือนจะไม่เปลี่ยนเส้นทาง stdout จริง ๆ แต่มันทำหน้าที่เป็นอินพุตบล็อกและหลีกเลี่ยงการกดแป้น

ข้อผิดพลาด openssh ที่เกี่ยวข้อง: https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14


0

หากคุณต้องการปิดการใช้งานนั้น (ดูเหมือนว่าจะเป็นพฤติกรรมเริ่มต้น) คุณจะต้องเปิดใช้งานssh-keep-aliveบนไคลเอนต์หรือฝั่งเซิร์ฟเวอร์

ถ้าคุณดูที่ ssh-keep-alive-options ใน man-pages คุณจะเห็นว่ามันถูกปิดใช้งานโดยค่าเริ่มต้น


0

คำตอบของฉันขึ้นอยู่กับ teru ฉันต้องการสคริปต์ตัวช่วย~/helperที่เซิร์ฟเวอร์ server.ip:

#!/bin/bash
TUBE=/tmp/sshCoLab_myfifo.$$;
mkfifo "$TUBE"
( <"$TUBE" "$@" ; rm "$TUBE" ; kill -TERM 0 ) &  
cat >"$TUBE" ;
rm "$TUBE" ;
kill -TERM 0 ;

ถ้ามันถูกเรียกเช่นกับ

ssh server.ip ~/helper echo hello from server

และดำเนินการecho hello from serverที่ server.ip จากนั้นไคลเอ็นต์ ssh จะยุติ

ถ้ามันถูกเรียกเช่นกับ

ssh server.ip ~/helper sleep 1000 &
CHID=$!

kill -9 $CHIDจะหยุดสคริปต์ที่เซิร์ฟเวอร์ด้วย สำหรับฉันkill -INT $CHIDไม่ทำงาน แต่ฉันไม่รู้ว่าทำไม

ในคำตอบของ teru คำสั่ง ssh จะรอตลอดไปเมื่อคำสั่งระยะไกลเสร็จสิ้นเพราะcatไม่จบ

คำตอบทั้งหมดที่มี ssh -t ไม่ได้ผลสำหรับฉันkillแต่เฉพาะกับ Ctrl-C

แก้ไข: ฉันพบว่าสิ่งนี้ได้ผลจาก Ubuntu 14.01 ใหม่ไปจนถึงกล่อง linux ทางวิทยาศาสตร์รุ่นเก่า - แต่ไม่ใช่ในทางกลับกัน ดังนั้นฉันคิดว่าไม่มีวิธีแก้ปัญหาทั่วไป แปลก.

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