Bash: nhắc nhở từ xa tương tác


16

Tôi có một tập lệnh kết nối với một máy chủ từ xa và kiểm tra xem một số gói đã được cài đặt chưa:

ssh root@server 'bash -s' < myscript.sh

myscript.sh:

OUT=`rpm -qa | grep ntpdate`
if [ "$OUT" != "" ] ; then
    echo "ntpdate already installed"
else
    yum install $1
fi

Ví dụ này có thể được đơn giản hóa. Đây là myscript2.shvấn đề tương tự:

read -p "Package is not installed. Do you want to install it (y/n)?" choise

Vấn đề của tôi là bash không thể đọc câu trả lời của tôi một cách tương tác.

Có cách nào để thực thi tập lệnh cục bộ từ xa mà không mất khả năng nhắc nhở người dùng không?


Bạn có thể xây dựng? Nó không thực sự rõ ràng những gì bạn đang yêu cầu? Một số mã của bạn sẽ hữu ích.
slm

1
Chỉ là một FYI, lý do điều này không hoạt động là vì bạn đang chuyển tập lệnh của bạn qua STDIN. Do đó, khi bash đọc từ STDIN, nó sẽ nhận được tập lệnh của bạn (hoặc không có gì vì nó đã đọc toàn bộ tập lệnh và không còn gì cả).
Patrick

1
Tài nguyên hữu ích liên quan đến việc này: backreference.org/2011/08/10/ trên
slm

Câu trả lời:


22

Hãy thử một cái gì đó như thế này:

$ ssh -t yourserver "$(<your_script)"

Các -tlực lượng phân bổ tty, $(<your_script)đọc toàn bộ tệp và trong trường hợp này chuyển nội dung dưới dạng một đối số ssh, sẽ được thực thi bởi trình bao của người dùng từ xa.

Nếu tập lệnh cần tham số, chuyển chúng sau tập lệnh:

$ ssh -t yourserver "$(<your_script)" arg1 arg2 ...

Làm việc cho tôi, không chắc chắn nếu nó phổ quát mặc dù.


3
Đó chính xác là những gì tôi đang tìm kiếm, cảm ơn bạn!
Anthony Ananich

Giải pháp hay, nhưng có cách nào để chuyển một đối số sang your script, trong khi vẫn giữ được những lợi thế của cú pháp bạn đã sử dụng trong câu trả lời của mình không? ssh -t yourserver "$(<your_script --some_arg)"Chỉ sử dụng kết quả trong bash: --some_arg: command not found.
sampablokuper

1
@sampablokuper: thửssh ... $(<script) script_arg1 script_arg2 ...
Mat

@Mat, cảm ơn, WFM :) Có thể thêm nó vào phần câu trả lời của bạn không?
sampablokuper

3

Vấn đề của bạn là sshbắt đầu đăng nhập, vỏ không tương tác trên máy từ xa. Giải pháp dễ dàng rõ ràng là sao chép tập lệnh vào máy chủ từ xa và chạy nó từ đó:

scp myscript.sh root@server:/tmp && ssh root@server /tmp/myscript.sh

Nếu sao chép không phải là một tùy chọn vì bất kỳ lý do gì, tôi sẽ sửa đổi tập lệnh thành kết nối đầu tiên và kiểm tra xem đã $1được cài đặt chưa, sau đó kết nối lại và cài đặt nếu cần:

OUT=$(ssh root@server rpm -qa | grep "$1");
if [ "$OUT" != "" ] ; then
    echo "$1 already installed"
else
   read -p "Package $1 is not installed. Do you want to install it (y/n)?" choice
   if [ "$choice" -eq "y" ]; then
       ssh root@server yum install "$1"
   fi
fi

Đó là những gì tôi sợ. Kết nối với ssh là hoạt động lâu nhất và tôi đã cố gắng tránh nó.
Anthony Ananich

@AnthonyAnanich Bạn có thể tiết kiệm thời gian thiết lập kết nối bằng cách thiết lập kết nối chính .
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Tôi đã nghĩ đến việc gợi ý điều đó nhưng tôi nghĩ nó sẽ không hoạt động với đề xuất của tôi. Nếu các kết nối ssh thứ nhất đóng vai trò là chủ, nó sẽ bị đóng sau khi $OUT=$(ssh root@server rpm -qa | grep "$1");thoát và kết nối thứ 2 sẽ mất nhiều thời gian như lần đầu tiên. Tôi có lầm không?
terdon

1
@terdon Chạy một cái gì đó giống ssh -M foo.example.com sleep 99999999hoặc ssh -M foo.example.com read <somefifolà chủ và giết nó một cách rõ ràng (bằng killhoặc echo done >somefifo) khi bạn hoàn thành.
Gilles 'SO- ngừng trở nên xấu xa'

0

Đây là một lời giải thích tốt .

Vì vậy, tôi đã điều chỉnh kịch bản thành

hostname
echo -n "Make your choice :"
read choice
echo "You typed " ${choice}
echo done

và điều này đã không làm việc.

Vì vậy, tôi đã chuyển tập lệnh sang điều khiển từ xa để tránh chuyển hướng cục bộ trên ssh. (Các lệnh của tôi nằm trong một tệp có tên f )

cat f | ssh user@remotehost.com 'cat >remf'
ssh user@remotehost bash remf

Điều này đã làm việc. Đây là đầu ra:

christian@clafujiu:~/tmp$ ssh localhost bash tmp/f
christian@localhost's password: 
Linux clafujiu 2.6.32-52-generic #114-Ubuntu SMP Wed Sep 11 19:00:15 UTC 2013 i686 GNU/Linux
Sun Nov 10 14:58:56 GMT 2013
Make your choice :abc
You typed  abc
done

Như @terdon đã đề cập rằng cường độ ban đầu là chạy các tập lệnh cục bộ từ xa, bản sao từ xa có thể được tự động hóa, đây chỉ là một ví dụ trên một dòng.

REMID=`cat f |ssh user@remotehost 'cat > remf_$$; echo $$'` ;ssh root@redtoadservices.com "bash remf_${REMID} ; rm -v remf_${REMID}"

2
Làm thế nào mà nó "làm việc"? Bạn đã chạy tập lệnh này bash -s < script.shgiống như OP đã làm chưa? Bạn có thể bao gồm lời giải thích trong câu trả lời của bạn thay vì liên kết với nó?
terdon

Rất tiếc, rất tiếc tôi đã quên thêm một cái gì đó quan trọng. Tôi cũng sao chép tập lệnh vào điều khiển từ xa để tránh chuyển hướng cục bộ. Tôi sẽ nối nó vào câu trả lời của tôi để làm cho nó rõ ràng.
X Tian

1
Nếu bạn sao chép tập lệnh vào điều khiển từ xa thì vấn đề sẽ biến mất. Vấn đề của OP là anh ta đang cố gắng cung cấp đầu vào tương tác cho một tập lệnh cục bộ chạy từ xa. Tất nhiên nó sẽ chạy của bạn sao chép nó qua. OP muốn chạy tập lệnh này khi kết nối với máy chủ từ xa, có lẽ là với nhiều máy chủ từ xa. Tôi nghi ngờ sao chép nó là thực tế trừ khi bạn tự động hóa nó.
terdon

0

Tôi đã tìm kiếm giải pháp cho vấn đề này nhiều lần trong quá khứ, tuy nhiên không bao giờ tìm thấy một giải pháp hoàn toàn thỏa đáng. Đường ống vào ssh làm mất tính tương tác của bạn. Hai kết nối (scp / ssh) chậm hơn và tệp tạm thời của bạn có thể bị bỏ lại xung quanh. Và toàn bộ kịch bản trên dòng lệnh thường kết thúc trong việc thoát khỏi địa ngục.

Gần đây tôi gặp phải rằng kích thước bộ đệm dòng lệnh thường khá lớn ('getconf ARG_MAX> 2MB nơi tôi nhìn). Và điều này khiến tôi suy nghĩ về cách tôi có thể sử dụng điều này và giảm thiểu vấn đề thoát.

Kết quả là:

ssh -t <host> /bin/bash "<(echo "$(cat my_script | base64 | tr -d '\n')" | base64 --decode)" <arg1> ...

hoặc sử dụng tài liệu ở đây và con mèo:

ssh -t <host> /bin/bash $'<(cat<<_ | base64 --decode\n'$(cat my_script | base64)$'\n_\n)' <arg1> ...

Tôi đã mở rộng ý tưởng này để tạo ra một kịch bản ví dụ BASH hoạt động hoàn toàn sshxcó thể chạy các tập lệnh tùy ý (không chỉ BASH), trong đó các đối số cũng có thể là các tệp đầu vào cục bộ, trên ssh. Xem tại đây .


Thú vị, nhưng làm thế nào và / hoặc khi nào thì điều này tốt hơn câu trả lời của Mat ?
Scott

1
Câu trả lời của Mat là một lượt đi đầu tiên tốt (mà tôi thường sử dụng), tuy nhiên nó không thể xử lý một tập lệnh có nội dung tùy ý, chẳng hạn như các "ký tự sẽ cần phải thoát. Và nó cũng bị giới hạn trong các tập lệnh BASH. Giải pháp của tôi là một trường hợp chung cho bất kỳ nội dung tập lệnh của bất kỳ ngôn ngữ kịch bản cài đặt nào. Hơn nữa, trong sshx tôi tiếp tục chứng minh các tệp đối số nối tiếp, khá tiện lợi.
SourceSimian

(1) Bạn có thể đăng MCVE của một kịch bản mà câu trả lời của Mat không thành công (và tác phẩm của bạn không)? (2) Xem Điều gì không ổn với echo echo $ (Stuff)  Ngoại hình của bạn echo "$(cat my_script | base64)" | base64 --decodetương đương (-ish) với cat my_script | base64 | base64 --decode, trông rất giống với no-op.
Scott

Xin chào @Scott. (1): Xem xét kịch bản : echo "ARG1=$1, USER=$USER, END". a) $ ssh host "$(<my_bash)" foo-> ARG1=, USER=user, END foo. b) $ ssh host bash "<(echo $(cat my_bash|base64) | base64 --decode)" foo-> ARG1=foo, USER=user, END. Ở đây (a) đang hoạt động hiệu quả: bash -c $'#!/bin/bash\necho "ARG1=$1, USER=$USER, END" foo'hoặc một cái gì đó tương tự. Lưu ý các arg không hoạt động. Trong đó (b) đang chạy : bash <(echo IyEvY...5EIgo= | base64 --decode) foo. (2) Tôi đã sử dụng base64 làm mã hóa vận chuyển.
SourceSimian
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.