Làm cách nào để tự động bắt đầu tmux trên phiên SSH?


92

Tôi có khoảng mười máy chủ mà tôi thường xuyên kết nối với SSH. Mỗi mục có một mục trong ~/.ssh/configtệp máy tính cục bộ của tôi .

Để tránh mất quyền kiểm soát quá trình chạy của tôi khi kết nối Internet của tôi chắc chắn bị ngắt, tôi luôn làm việc trong một tmuxphiên. Tôi muốn có một cách để tmux tự động kết nối mỗi khi kết nối SSH được bắt đầu, vì vậy tôi không phải luôn nhập tmux attach || tmux newsau khi tôi SSH.

Thật không may, điều này không trở nên đơn giản như tôi hy vọng ban đầu.

  • Tôi không muốn thêm bất kỳ lệnh nào ~/.bashrcvào máy chủ vì tôi chỉ muốn nó cho các phiên SSH, không phải phiên cục bộ.
  • Thêm tmux attach || tmux newvào ~/.ssh/rctrên các máy chủ chỉ đơn giản là kết quả trong các lỗi not a terminalđược ném sau khi kết nối, ngay cả khi các RequestTTY forcetùy chọn được thêm vào dòng cho rằng máy chủ trong tập tin cấu hình SSH địa phương của tôi.

1
Vì đây tiếp tục là một câu hỏi phổ biến và được đề cập cụ thể ~/.ssh/config: hầu hết các bạn đến đây có thể không tìm kiếm bất kỳ câu trả lời nào trong số năm câu trả lời đầu tiên, mà là câu trả lời thứ sáu ( stackoverflow.com/a/52838493/5354137 ). Với bất kỳ tmuxphiên bản hợp lý nào gần đây cũng là cách làm hợp lý nhất.
Sixtyfive

Câu trả lời:


90

Cấu hình phía máy chủ:

Để tự động khởi động tmux trên máy chủ từ xa của bạn khi đăng nhập thông thường qua SSH (và chỉ SSH), hãy chỉnh sửa ~/.bashrcngười dùng hoặc người chủ của bạn (hoặc cả hai) trên máy chủ từ xa cho phù hợp:

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

Lệnh này tạo một phiên tmux được gọi ssh_tmuxnếu không có phiên nào tồn tại hoặc gắn lại với phiên đã tồn tại với tên đó. Trong trường hợp kết nối của bạn bị ngắt hoặc khi bạn quên một phiên cách đây vài tuần, mỗi lần đăng nhập SSH sẽ tự động đưa bạn trở lại phiên tmux-ssh mà bạn đã bỏ lại.

Kết nối từ khách hàng của bạn:

Không có gì đặc biệt, chỉ là ssh user@hostname.


4
Tôi đang tìm kiếm này, cũng tôi đã sử dụng một đoạn mã rất giống với bạn một số thời gian trước đây, nhưng phiên là tên người dùng (thay đổi ssh_tmuxđể $USER)
Iacchus

3
Xem câu trả lời của moneytoo để biết bình luận hữu ích về $SSH_TTYvs $SSH_CONNECTIONquá.
Ông Tao

2
bạn có thể sử dụng tmux new-session -A -s ssh_tmuxđể thay thế phiên tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxngắn hơn nhiều, nếu khó hiểu hơn một chút, hãy -Ayêu cầu tmux đính kèm phiên nếu nó đã tồn tại
Gradient

3
Để tránh phá vỡ "scp", bạn cũng sẽ cần phải kiểm tra xem đây là một vỏ tương tác:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode

2
@janfrode không dựa vào $PS1, [[ $- == *i* ]]thay vào đó hãy sử dụng vì PS1 có thể được định nghĩa ngay cả khi nó không phải là một trình bao tương tác.
Enrico

54

Được rồi, tôi đã tìm thấy một giải pháp gần như thỏa đáng. Trong địa phương của tôi ~/.bashrc, tôi đã viết một hàm:

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

về cơ bản nó sẽ ghi đè hàm terminal ssh để gọi chương trình ssh tích hợp sẵn với các đối số đã cho, theo sau là "tmux attach || tmux new".

( $@Biểu thị tất cả các đối số được cung cấp trên dòng lệnh, vì vậy ssh -p 123 user@hostnamesẽ được mở rộng thành ssh -t -p 123 user@hostname "tmux attach || tmux new")

(Đối -tsố tương đương RequestTTY Forcevà cần thiết cho lệnh tmux.)


22
Nếu phiên bản của bạn tmuxhỗ trợ nó, hãy cân nhắc sử dụng phiên bản tmux new -A foonày sẽ đính kèm vào phiên hiện có được đặt tên foonếu có thể, tạo phiên bản này nếu cần. Điều này cho phép bạn đơn giản hóa chức năng của mình thành /usr/bin/ssh -t "$@" tmux new -A(và nhớ trích dẫn $@!).
chepner

1
Lưu ý: nếu một số máy bạn kết nối thường xuyên không được cài đặt tmux, bạn có thể nói function sshthoặc tương tự để có thể tiếp tục sử dụng sshbình thường. Nếu không, chỉ cần gõ /usr/bin/sshtại dấu nhắc lệnh bất cứ khi nào kết nối với một máy mà không tmux :)
Alex Ryan

1
Nếu lười, bạn có thể sử dụng ssht để kết nối với các phiên tmux từ xa. Người dùng OS X có thể khai thác nó thông qua brew và người dùng Linux có thể tạo một gói thông qua fpm với Makefile này hoặc chỉ cần sao chép sshtvào ~/bin.
brejoc

1
Haha, tốt lắm! Có vẻ như tôi hơi quá mức cần thiết để bọc một lớp lót bash này trong toàn bộ repo Github với Makefiles và pha chế và tương tự nhưng này, càng dễ thì càng tốt!
Alex Ryan,

1
Đã giải quyết:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm

23

Kết nối:

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

Trong phiên:

Sử dụng Ctrl+dđể phiên kết thúc (đóng cửa sổ tmux) hoặc Ctrl+b dđến cửa sổ mới tạm thời từ phiên và kết nối với nó một lần nữa sau đó.

Nhớ lại! Nếu phiên khởi động lại máy chủ của bạn bị mất!

Khi bạn ở trong tmux bất cứ lúc nào, bạn có thể sử dụng Ctrl+b sđể xem danh sách phiên và chuyển đổi hiện tại sang phiên khác.

Sửa .bashrc của bạn:

Tôi khuyên bạn nên xác định chức năng phổ quát trong .bashrc:

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

Nó sử dụng 22cổng theo mặc định. Xác định cả bí danh kết nối nhanh của bạn:

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

Đăng nhập mà không cần mật khẩu:

Và nếu bạn không muốn nhập mật khẩu mọi lúc thay vì tạo .sshkhóa để đăng nhập tự động :

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

Đặt khóa công khai của bạn vào máy chủ từ xa:

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

Mẹo bổ sung:

Nếu bạn muốn sử dụng session-id tạm thời tương ứng với việc sử dụng phiên bash cục bộ làm id tmux :

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

1
Một lừa gọn gàng để tránh điều đó ||trong một số trường hợp sử dụng là bao gồm new-sessiontrong .tmux.confvà chỉ luôn luôn sử dụng tmux a -t 0.
Florian Wendelborn

4
Trong các phiên bản tmux mới hơn, bạn cũng có thể sử dụng tmux new-session -Anó sẽ đính kèm nếu nó tồn tại nếu không nó sẽ tạo một cái mới.
dragon788

15

Tôi đã sử dụng các dòng từ @kingmeffisto (tôi không được phép bình luận câu trả lời đó) và tôi đã thêm một lối thoát để việc chấm dứt tmux cũng chấm dứt kết nối ssh. Tuy nhiên, điều này đã làm hỏng các phiên SFTP nên tôi phải kiểm tra $SSH_TTYthay vì $SSH_CONNECTION.

EDIT 4/2018: Đã thêm thử nghiệm cho thiết bị đầu cuối tương tác thông qua [[ $- =~ i ]]để cho phép các công cụ như Ansible hoạt động.

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

14

Như được mô tả trong bài đăng blog này, bạn có thể ssh và sau đó đính kèm vào phiên tmux hiện có bằng một lệnh duy nhất:

ssh hostname -t tmux attach -t 0

Đó là những gì câu trả lời của tôi làm (mặc dù tôi sử dụng tmux attach || tmux newđể phiên tmux mới không được tạo cho mọi kết nối). Phần khó khăn là lệnh chính xác ssh -t user@host tmux attach || tmux newvà cách duy nhất để đặt bí danh cho một thứ gì đó cần đối số bên trong chuỗi lệnh là tạo một hàm mới, giống như tôi đã làm ở trên.
Alex Ryan

Tôi biết, nhưng một số người (như tôi) có thể thích một lớp lót mà không liên quan đến việc xác định một chức năng
Fabian PEDREGOSA

3
Điều này kết nối với một phiên được gọi là '0'. Đó là, các hình thức nói chung làssh [hostname] -t tmux attach -t [sessionName]
David Doria

1
Điều này thực sự hiệu quả với tôi .. Kết hợp điều này sẽ unix.stackexchange.com/a/116674 .. vì vậy bây giờ GUI putty của tôi trông giống như thế này .. imgur.com/uFhxN30 . Tôi có thể ngắt kết nối các phiên bằng Cntrl + b + d. Rất đơn giản và thuận tiện ..
alpha_989

14

tmux 3.1 hoặc mới hơn¹ trên máy điều khiển từ xa

Vào địa phương của bạn ~/.ssh/config, put²:

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

Không liên quan, nhưng nếu bạn đang xử lý các ký tự không phải ASCII, tôi khuyên bạn nên thay đổi điều đó thành tmux -u …để bật hỗ trợ Unicode một cách rõ ràng ngay cả trên các máy không đặt các biến môi trường thích hợp.

tmux 3.0a trở lên trên máy điều khiển từ xa

Gần giống như trên, nhưng thay đổi dòng cuối cùng thành³:

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

¹ Kể từ năm 2020-10-29, danh sách các bản phân phối được vận chuyển với tmux 3.1 hoặc mới hơn đã khá dài.

² newlà viết tắt của new-session.

³ atlà viết tắt của attach-session.


Phương pháp thay thế bằng cách sử dụng authorized_keystệp của điều khiển từ xa :

Nếu bạn không muốn có ~/.ssh/configtệp vì bất kỳ lý do gì hoặc muốn máy từ xa buộc máy kết nối phải kết nối / mở phiên, hãy thêm tệp này vào điều khiển từ xa của bạn ~/.ssh/authorized_keys:

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

Tất nhiên, điều này sẽ hoạt động đối với tất cả các máy khách đã cài đặt khóa riêng tương ứng, có thể là tăng hoặc giảm, tùy thuộc vào những gì bạn muốn. Có nguy cơ xảy ra sự cố, có thể không kết nối được nữa.


tại sao tmux atthay vì tmux a? Ngoài ra, sẽ là khôn ngoan nếu sử dụng một phiên được đặt tên cho việc này hoặc tmux sẽ gắn vào các phiên hiện có "ngẫu nhiên" khi đăng nhập vào máy chủ.
Eric

Làm thế nào để bạn tạm dừng phiên tmux? ssh chuyển sang trạng thái lấp lửng kindda sau khi đánh Ctrl+A Ctrl+Z.
Eric

Nó chỉ ngắt kết nối. Theo như tôi được biết, đó là hành vi mà tôi mong đợi và hài lòng.
Sáu mươi lăm

1
Ctrl-B Dcông trình điều trị so với Ctrl-B Ctrl-Z. Cảm ơn!
Eric

1
Đây hẳn là câu trả lời được bình chọn nhiều nhất. Tôi đã tìm kiếm chính xác (2).
cduguet

1

byobu là một trình bao bọc hữu ích tốt đẹp cho tmux / screen. Kết nối với một phiên hiện có nếu có hoặc tạo một phiên mới.

Tôi sử dụng nó với autossh để kết nối lại phiên ssh một cách duyên dáng. Rất khuyến khích trong trường hợp sự cố kết nối không liên tục.

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

Bạn có thể thấy điều này hữu ích - sử dụng ssh trong một vòng lặp và kết nối lại hoặc kết nối với một phiên tmux hiện có để bạn có một cách dễ dàng và đáng tin cậy để kết nối lại sau khi mất mạng

#!/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

Đây là cách thực sự tạo ra trải nghiệm người dùng tuyệt vời. Nó tự động khởi động tmux bất cứ khi nào bạn mở thiết bị đầu cuối (cả vật lý và ssh). Bạn có thể bắt đầu công việc của mình trên một thiết bị, thoát khỏi thiết bị đầu cuối và tiếp tục trên thiết bị kia. Nếu nó phát hiện ai đó đã được đính kèm vào phiên, nó sẽ tạo phiên mới. Đặt nó trên máy chủ , tùy thuộc vào trình bao của bạn ~/.zshrchoặc ~/.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

Tôi biết tôi đang phục hồi một chủ đề cũ nhưng tôi đã thực hiện một số công việc trên giải pháp bashrc và tôi nghĩ rằng nó có một số công dụng:

#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

Hiện tại có giới hạn ở 10 (11) phiên - Tôi không muốn giết máy chủ của mình bằng một vòng lặp vô hạn trong bashrc. Nó dường như hoạt động khá đáng tin cậy, ngoại trừ lỗi tmux không thành công trên các máy khách danh sách nếu phiên không tồn tại.


0

Cách này cho phép bạn kết nối lại với phiên bản tmux cũ nếu phiên ssh của bạn giảm xuống. Tất nhiên, exectiết kiệm một ngã ba.

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
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.