จะเริ่ม tmux โดยอัตโนมัติในเซสชัน SSH ได้อย่างไร?


92

ฉันมีเซิร์ฟเวอร์สิบเครื่องหรือมากกว่านั้นที่ฉันเชื่อมต่อกับ SSH เป็นประจำ แต่ละรายการมีรายการใน~/.ssh/configไฟล์ของคอมพิวเตอร์ในระบบของฉัน

เพื่อหลีกเลี่ยงการสูญเสียการควบคุมกระบวนการทำงานของฉันเมื่อการเชื่อมต่ออินเทอร์เน็ตของฉันลดลงอย่างหลีกเลี่ยงไม่ได้ฉันมักจะทำงานในtmuxเซสชัน ฉันต้องการวิธีเชื่อมต่อ tmux โดยอัตโนมัติทุกครั้งที่เริ่มการเชื่อมต่อ SSH ดังนั้นฉันจึงไม่จำเป็นต้องพิมพ์tmux attach || tmux newหลังจากฉัน SSH เข้าเสมอ

น่าเสียดายที่สิ่งนี้ไม่ง่ายอย่างที่หวังไว้ในตอนแรก

  • ฉันไม่ต้องการเพิ่มคำสั่งใด ๆ~/.bashrcในเซิร์ฟเวอร์เพราะฉันต้องการให้ใช้เฉพาะเซสชัน SSH เท่านั้นไม่ใช่เซสชันภายใน
  • การเพิ่มtmux attach || tmux newลง~/.ssh/rcในเซิร์ฟเวอร์จะส่งผลให้เกิดข้อผิดพลาดnot a terminalหลังจากการเชื่อมต่อแม้ว่าRequestTTY forceจะมีการเพิ่มตัวเลือกในบรรทัดสำหรับเซิร์ฟเวอร์นั้นในไฟล์กำหนดค่า SSH ในเครื่อง

1
เนื่องจากคำถามนี้ยังคงเป็นคำถามยอดนิยมและมีการกล่าวถึงเป็นพิเศษ~/.ssh/configพวกคุณส่วนใหญ่ที่มาที่นี่อาจไม่ได้มองหาคำตอบห้าข้อแรก แต่สำหรับข้อที่หก ( stackoverflow.com/a/52838493/5354137 ) ด้วยtmuxเวอร์ชันล่าสุดที่สมเหตุสมผลซึ่งเป็นวิธีที่เหมาะสมที่สุดในการทำสิ่งต่างๆ
Sixtyfive

คำตอบ:


90

การกำหนดค่าฝั่งเซิร์ฟเวอร์:

หากต้องการเริ่ม tmux โดยอัตโนมัติบนเซิร์ฟเวอร์ระยะไกลของคุณเมื่อเข้าสู่ระบบโดยปกติผ่าน SSH (และเฉพาะ SSH) ให้แก้ไข~/.bashrcผู้ใช้หรือรูทของคุณ (หรือทั้งสองอย่าง) บนเซิร์ฟเวอร์ระยะไกลตาม:

if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]]; then
  tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmux
fi

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

เชื่อมต่อจากลูกค้าของคุณ:

ssh user@hostnameไม่มีอะไรพิเศษเพียง


4
ฉันกำลังมองหาสิ่งนี้เช่นกันฉันใช้รหัสชิ้นหนึ่งที่คล้ายกับของคุณเมื่อไม่นานมานี้ แต่เซสชันนี้เป็นชื่อผู้ใช้ (เปลี่ยนssh_tmuxเป็น$USER)
Iacchus

3
ดูคำตอบของ moneytoo สำหรับความคิดเห็นที่เป็นประโยชน์เกี่ยว$SSH_TTYกับ vs $SSH_CONNECTIONด้วย
Mr. Tao

2
คุณสามารถใช้tmux new-session -A -s ssh_tmuxเพื่อแทนที่ที่tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxสั้นกว่ามากหากสับสนอีกเล็กน้อย-Aบอก tmux ให้แนบเซสชันหากมีอยู่แล้ว
Gradient

3
เพื่อหลีกเลี่ยงการทำลาย "scp" คุณต้องตรวจสอบด้วยว่านี่เป็นเชลล์แบบโต้ตอบหรือไม่:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
61

2
@janfrode ไม่ต้องพึ่งพา$PS1ใช้[[ $- == *i* ]]แทนเนื่องจาก PS1 อาจถูกกำหนดแม้ว่าจะไม่ใช่เชลล์แบบโต้ตอบ
Enrico

54

ได้เลยฉันพบวิธีแก้ปัญหาที่น่าพอใจที่สุด ในพื้นที่ของ~/.bashrcฉันฉันเขียนฟังก์ชัน:

function ssh () {/usr/bin/ssh -t $@ "tmux attach || tmux new";}

ซึ่งโดยทั่วไปจะเขียนทับฟังก์ชันเทอร์มินัล ssh เพื่อเรียกโปรแกรม ssh ในตัวด้วยอาร์กิวเมนต์ที่กำหนดตามด้วย"tmux attach || tmux new".

( $@หมายถึงอาร์กิวเมนต์ทั้งหมดที่มีให้ในบรรทัดคำสั่งดังนั้นssh -p 123 user@hostnameจะขยายเป็นssh -t -p 123 user@hostname "tmux attach || tmux new")

( -tอาร์กิวเมนต์เทียบเท่าRequestTTY Forceและจำเป็นสำหรับคำสั่ง tmux)


22
หากเวอร์ชันของคุณtmuxรองรับให้พิจารณาใช้tmux new -A fooซึ่งจะแนบกับเซสชันที่มีอยู่ซึ่งตั้งชื่อว่าfooถ้าเป็นไปได้สร้างขึ้นหากจำเป็น สิ่งนี้ช่วยให้คุณลดความซับซ้อนของฟังก์ชันเป็น/usr/bin/ssh -t "$@" tmux new -A(และอย่าลืมอ้าง$@!)
chepner

1
หมายเหตุ: หากเครื่องบางเครื่องที่คุณเชื่อมต่อเป็นประจำไม่ได้ติดตั้ง tmux คุณอาจต้องการพูดfunction sshtหรือชอบเพื่อให้คุณสามารถใช้งานได้sshตามปกติ มิฉะนั้นเพียงพิมพ์/usr/bin/sshที่พรอมต์คำสั่งเมื่อใดก็ตามที่เชื่อมต่อกับเครื่องโดยไม่ใช้ tmux :)
Alex Ryan

1
หากคุณขี้เกียจคุณสามารถใช้sshtเพื่อเชื่อมต่อกับเซสชัน tmux ระยะไกลของคุณได้ ผู้ใช้ OS X สามารถแตะมันผ่านการชงและผู้ใช้ลินุกซ์สามารถสร้างแพคเกจผ่านFPMกับเรื่องนี้Makefileหรือเพียงแค่คัดลอกไปssht ~/bin
brejoc

1
ฮาฮาดี! ดูเหมือนจะเกินความจำเป็นสำหรับฉันที่จะห่อ bash one-liner นี้ใน repo Github ทั้งหมดด้วย Makefiles และการชง แต่เดี๋ยวก่อนยิ่งง่ายขึ้นก็ยิ่งดี!
Alex Ryan

1
แก้ไข:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm

23

เชื่อมต่อ:

ssh user@host -t "tmux new-session -s user || tmux attach-session -t user"

ระหว่างเซสชั่น:

ใช้Ctrl+dเพื่อสิ้นสุดเซสชัน (ปิดหน้าต่าง tmux) หรือCtrl+b dเพื่อแยกออกจากเซสชันชั่วคราวและเชื่อมต่ออีกครั้งในภายหลัง

จำไว้! หากเซิร์ฟเวอร์ของคุณรีสตาร์ทเซสชันสูญหาย!

เมื่อคุณอยู่ใน tmux ทุกเมื่อคุณสามารถใช้Ctrl+b sเพื่อดูรายการเซสชันและเปลี่ยนปัจจุบันเป็นรายการอื่น

แก้ไข. bashrc ของคุณ:

ขอแนะนำให้คุณกำหนดฟังก์ชันสากลใน.bashrc:

function tmux-connect {
    TERM=xterm-256color ssh -p ${3:-22} $1@$2 -t "tmux new-session -s $1 || tmux attach-session -t $1"
}

ใช้22พอร์ตโดยค่าเริ่มต้น กำหนดนามแฝงการเชื่อมต่อที่รวดเร็วของคุณด้วย:

alias office-server='tmux-connect $USER 192.168.1.123'
alias cloud-server='tmux-connect root my.remote.vps.server.com 49281'

เข้าสู่ระบบโดยไม่ใช้รหัสผ่าน:

และหากคุณไม่ต้องการพิมพ์รหัสผ่านทุกครั้งมากกว่าการสร้าง.sshคีย์เพื่อเข้าสู่ระบบโดยอัตโนมัติ :

ssh-keygen -t rsa
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_rsa

ใส่กุญแจสาธารณะของคุณไปยังโฮสต์ระยะไกล:

ssh-copy-id -p <port> user@hostname

เคล็ดลับเพิ่มเติม:

หากคุณต้องการใช้session-id ชั่วคราวซึ่งสอดคล้องกับ local bash session ใช้เป็นtmux id:

SID=$USER-$BASHPID
ssh user@host -t "tmux new-session -s $SID || tmux attach-session -t $SID"

1
เคล็ดลับที่เรียบร้อยเพื่อหลีกเลี่ยงการว่า||ในบางกรณีการใช้งานคือการรวมnew-sessionในและเพียงแค่การใช้งานเสมอ.tmux.conf tmux a -t 0
Florian Wendelborn

4
ใน tmux เวอร์ชันที่ใหม่กว่าคุณสามารถใช้tmux new-session -Aซึ่งจะแนบหากมีอยู่มิฉะนั้นจะสร้างใหม่
dragon788

15

ฉันใช้บรรทัดจาก @kingmeffisto (ฉันไม่ได้รับอนุญาตให้แสดงความคิดเห็นคำตอบนั้น) และฉันได้เพิ่มทางออกดังนั้นการยกเลิก tmux จะยุติการเชื่อมต่อ ssh ด้วย อย่างไรก็ตามเรื่องนี้ยากจนประชุม SFTP เพื่อให้ฉันได้ตรวจสอบแทน$SSH_TTY$SSH_CONNECTION

แก้ไข 4/2018: เพิ่มการทดสอบเทอร์มินัลแบบโต้ตอบผ่านทาง[[ $- =~ i ]]เพื่อให้เครื่องมือเช่น Ansible ทำงานได้

if [ -z "$TMUX" ] && [ -n "$SSH_TTY" ] && [[ $- =~ i ]]; then
    tmux attach-session -t ssh || tmux new-session -s ssh
    exit
fi

14

ตามที่อธิบายไว้ในโพสต์บล็อกนี้คุณสามารถ ssh แล้วแนบกับเซสชัน tmux ที่มีอยู่ด้วยคำสั่งเดียว

ssh hostname -t tmux attach -t 0

นั่นคือสิ่งที่คำตอบของฉัน (แม้ว่าฉันจะใช้tmux attach || tmux newเพื่อไม่ให้สร้างเซสชัน tmux ใหม่สำหรับการเชื่อมต่อทุกครั้ง) ส่วนที่ยุ่งยากคือคำสั่งที่ถูกต้องssh -t user@host tmux attach || tmux newและวิธีเดียวที่จะใช้แทนสิ่งที่ต้องการอาร์กิวเมนต์ภายในสตริงคำสั่งคือการสร้างฟังก์ชันใหม่เช่นที่ฉันทำข้างต้น
Alex Ryan

ฉันรู้ แต่บางคน (เช่นฉัน) อาจชอบซับเดียวที่ไม่เกี่ยวข้องกับการกำหนดฟังก์ชัน
Fabian Pedregosa

3
สิ่งนี้เชื่อมต่อกับเซสชันที่เรียกว่า "0" นั่นคือรูปแบบทั่วไปคือssh [hostname] -t tmux attach -t [sessionName]
David Doria

1
นี้ทำงานได้ดีจริงๆสำหรับฉัน .. รวมนี้จะunix.stackexchange.com/a/116674 .. ดังนั้นตอนนี้รูปลักษณ์ที่ฉาบ GUI ของฉันเช่นนี้ .. imgur.com/uFhxN30 ฉันสามารถยกเลิกการเชื่อมต่อเซสชันด้วย Cntrl + b + d ง่ายและสะดวกมาก ..
alpha_989

14

tmux 3.1 หรือใหม่กว่า¹บนเครื่องระยะไกล

ในท้องถิ่นของคุณใส่~/.ssh/config²:

Host myhost
  Hostname host
  User user
  RequestTTY yes
  RemoteCommand tmux new -A -s foobar

ไม่เกี่ยวข้อง แต่ถ้าคุณกำลังจัดการกับอักขระที่ไม่ใช่ ASCII ฉันขอแนะนำให้เปลี่ยนเป็นtmux -u …เพื่อเปิดใช้งานการสนับสนุน Unicode อย่างชัดเจนแม้ในเครื่องที่ไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมที่เหมาะสม

tmux 3.0a หรือเก่ากว่าบนเครื่องระยะไกล

เกือบจะเหมือนกับด้านบน แต่เปลี่ยนบรรทัดสุดท้ายเป็น:

  RemoteCommand tmux at -t foobar || tmux new -s foobar

¹ในปี 2020-10-29 รายการการจัดจำหน่ายที่จัดส่งด้วย tmux 3.1 หรือใหม่กว่านั้นค่อนข้างยาวแล้ว

² newย่อมาจากnew-session.

³ atย่อมาจากattach-session.


วิธีอื่นโดยใช้authorized_keysไฟล์ของรีโมท:

หากคุณไม่ต้องการมี~/.ssh/configไฟล์ไม่ว่าด้วยเหตุผลใดก็ตามหรือต้องการให้เครื่องระยะไกลบังคับให้เครื่องเชื่อมต่อเชื่อมต่อ / เปิดเซสชันให้เพิ่มสิ่งนี้ลงในรีโมตของคุณ~/.ssh/authorized_keys:

command="tmux at -t foobar || tmux new -s foobar" pubkey user@client

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


ทำไมtmux atแทนที่จะเป็นtmux a? นอกจากนี้ควรใช้เซสชันที่มีชื่อสำหรับสิ่งนี้หรือ tmux จะแนบกับเซสชันที่มีอยู่ "แบบสุ่ม" เมื่อล็อกอินเข้าสู่โฮสต์
Eric

คุณระงับเซสชัน tmux ได้อย่างไร? SSH จะเข้าสู่ kindda Ctrl+A Ctrl+Zรัฐทอดทิ้งหลังจากตี
Eric

มันก็ตัดการเชื่อมต่อ เท่าที่ฉันกังวลนั่นคือพฤติกรรมที่ฉันคาดหวังและมีความสุข
Sixtyfive

1
Ctrl-B Dใช้งานได้ดีเมื่อเทียบกับCtrl-B Ctrl-Z. ขอบคุณ!
Eric

1
นี่ควรจะเป็น imho คำตอบที่ได้รับการโหวตมากที่สุด ฉันกำลังมองหา (2)
cduguet

1

byobuเป็นกระดาษห่อหุ้มที่มีประโยชน์สำหรับ tmux / screen เชื่อมต่อกับเซสชันที่มีอยู่หากมีอยู่หรือสร้างขึ้นใหม่

ฉันใช้มันกับautosshซึ่งเชื่อมต่อเซสชัน ssh ใหม่อย่างสง่างาม แนะนำเป็นอย่างยิ่งในกรณีที่มีปัญหาการเชื่อมต่อไม่ต่อเนื่อง

function ssh-tmux(){
  if ! command -v autossh &> /dev/null; then echo "Install autossh"; fi
  autossh -M 0 $* -t 'byobu || {echo "Install byobu-tmux on server..."} && bash'
}

1

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

#!/bin/bash
#
# reconnect to or spawn a new tmux session on the remote host via ssh.
# If the network connection is lost, ssh will reconnect after a small
# delay.
#

SSH_HOSTNAME=$1
TMUX_NAME=$2
PORT=$3

if [[ "$PORT" != "" ]]
then
    PORT="-p $PORT"
fi

if [ "$TMUX_NAME" = "" ]
then
    SSH_UNIQUE_ID_FILE="/tmp/.ssh-UNIQUE_ID.$LOGNAME"

    if [ -f $SSH_UNIQUE_ID_FILE ]
    then
        TMUX_NAME=`cat $SSH_UNIQUE_ID_FILE`
        TMUX_NAME=`expr $TMUX_NAME + $RANDOM % 100`
    else
        TMUX_NAME=`expr $RANDOM % 1024`
    fi

    echo $TMUX_NAME > $SSH_UNIQUE_ID_FILE

    TMUX_NAME="id$TMUX_NAME"
fi

echo Connecting to tmux $TMUX_NAME on hostname $SSH_HOSTNAME

SLEEP=0
while true; do

    ssh $PORT -o TCPKeepAlive=no -o ServerAliveInterval=15 -Y -X -C -t -o BatchMode=yes $SSH_HOSTNAME "tmux attach-session -t $TMUX_NAME || tmux -2 -u new-session -s $TMUX_NAME"
    SLEEP=10
    if [ $SLEEP -gt 0 ]
    then
        echo Reconnecting to session $TMUX_NAME on hostname $SSH_HOSTNAME in $SLEEP seconds
        sleep $SLEEP
    fi
done

1

นี่คือสิ่งที่สร้างประสบการณ์ผู้ใช้ที่ยอดเยี่ยมอย่างแท้จริง มันเริ่ม tmux โดยอัตโนมัติทุกครั้งที่คุณเปิดเทอร์มินัล (ทั้งทางกายภาพและ ssh) คุณสามารถเริ่มงานบนอุปกรณ์เครื่องหนึ่งออกจากเครื่องเทอร์มินัลและดำเนินการต่อในอีกเครื่องหนึ่ง หากตรวจพบว่ามีคนเชื่อมต่อกับเซสชันอยู่แล้วระบบจะสร้างเซสชันใหม่ วางไว้บนเซิร์ฟเวอร์ขึ้นอยู่กับเชลล์ของคุณ~/.zshrcหรือ~/.bashrc.

 if [[ -z "$TMUX" ]] ;then
     ID="$( tmux ls | grep -vm1 attached | cut -d: -f1 )" # get the id of a deattached session
     if [[ -z "$ID" ]] ;then # if not available attach to a new one
         tmux new-session
     else
         tmux attach-session -t "$ID" # if available attach to it
     fi
fi

0

ฉันรู้ว่าฉันกำลังฟื้นฟูเธรดเก่า แต่ฉันได้ทำงานกับโซลูชัน bashrc แล้วและฉันคิดว่ามันมีประโยชน์:

#attach to the next available tmux session that's not currently occupied
if [[ -z "$TMUX" ]] && [ "SSH_CONNECTION" != "" ];
then
    for i in `seq 0 10`; do #max of 10 sessions - don't want an infinite loop until we know this works
            SESH=`tmux list-clients -t "$USER-$i-tmux" 2>/dev/null` #send errors to /dev/null - if the session doesn't exist it will throw an error, but we don't care
            if [ -z "$SESH" ] #if there's no clients currently connected to this session
            then
                tmux attach-session -t "$USER-$i-tmux" || tmux new-session -s "$USER-$i-tmux" #attach to it
                break #found one and using it, don't keep looping (this will actually run after tmux exits AFAICT)
            fi #otherwise, increment session counter and keep going
    done

fi

ตอนนี้มีจำนวนสูงสุดที่ 10 (11) เซสชัน - ฉันไม่ต้องการฆ่าเซิร์ฟเวอร์ของฉันด้วยการวนซ้ำที่ไม่มีที่สิ้นสุดใน bashrc ดูเหมือนว่าจะทำงานได้ค่อนข้างน่าเชื่อถือนอกเหนือจากข้อผิดพลาดของ tmux ที่ล้มเหลวในรายการไคลเอ็นต์หากไม่มีเซสชัน


0

วิธีนี้ช่วยให้คุณสามารถเชื่อมต่อกับอินสแตนซ์ tmux เก่าอีกครั้งหากเซสชัน ssh ของคุณลดลง execบันทึกส้อมของหลักสูตร

if [ -z "$TMUX"  ]; then
  pid=$(tmux ls | grep -vm1 "(attached)" | cut -d: -f1)
  if [ -z "$pid" ]; then
    tmux new -d -s $pid
  fi

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