วิธีรันสคริปต์ภายในเซสชัน telnet


5

ฉันต้องการเชื่อมต่อกับโฮสต์ระยะไกลโดยใช้ telnet ไม่มีการยืนยันชื่อผู้ใช้ / รหัสผ่าน เพียงแค่

telnet remotehost

จากนั้นฉันต้องป้อนคำสั่งบางอย่างเพื่อเริ่มต้น

แล้วฉันต้องทำซ้ำคำสั่งต่อไปนี้:

cmd argument

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

โดยพื้นฐานแล้วสคริปต์จะเป็นอย่างไร:

initialization_cmd  #some initial comands
while read line
do    
  cmd $line
  #here the remote host will output results, how can I put the results into a variable?
  # here I want to judge the results, like
  if $results contain "OK";then
       echo $line >>good_result_log
  else
       echo $line >> bad_result_log
  fi     
done < local_file

 the good_result_log and bad_result_log are local files

เป็นไปได้หรือไม่ ขอบคุณ!

หมายเหตุ: ฉันไม่สามารถควบคุม B ได้ฉันสามารถเรียกใช้ cmds เริ่มต้นและ cmd $ บรรทัดบน B เท่านั้น


2
คาดหวังว่าจะเป็นเพื่อนของคุณ (ไม่ใช่ของฉัน :))

นี่คือการผสมผสานของสองคำถามที่แตกต่างกันวิธีการเขียนสคริปต์ของคุณ และบางทีวิธีการอ่านจากไฟล์ในเครื่องหรือบางสิ่ง คุณอาจจะ telnet จาก A ถึง B จากนั้นใช้ FTP ที่ปลอดภัยจาก B ถึง A เพื่อรับไฟล์ที่คุณต้องการ
barlop

ฉันหวังว่าจะเชื่อมต่อเครื่องระยะไกลโดยใช้ telnet เพียงครั้งเดียวและทำการเชื่อมต่อต่อไปคาดว่าจะใช้ได้หรือไม่?
wenzi

คำตอบ:


1

นี่ไม่ใช่สิ่งที่คุณสามารถทำได้หากคุณเปิดใช้งาน telnet ด้วยตนเอง - อย่างไรก็ตามฉันจะแก้ไขไฟล์สคริปต์ของคุณเองและเปิดใช้ telnet จากภายในประมวลผลบรรทัดเอาต์พุตจาก telnet เป็นอินพุตภายใน bash

ฉันไม่สามารถยกตัวอย่างได้จริง ๆ เพราะฉันเพิ่งทำสิ่งนี้จาก Windows Script และไม่ใช่ Bash แต่ฉันรู้ว่าสิ่งนี้จะบรรลุสิ่งที่คุณต้องการ


@wenzi: หากคุณเข้าถึง“ netcat” คุณอาจต้องการใช้มันแทน“ telnet”
Scott

ทำไม? คุณเจาะจงได้ไหม ขอบคุณ!
wenzi

1

bash ไม่ใช่เครื่องมือที่เหมาะสมสำหรับงานนี้

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

หากคุณคุ้นเคยกับภาษา Python (แทนที่จะเป็นภาษา Tcl ที่ใช้โดยคาดหวัง) ให้พิจารณา pexpect แทน.


0

ใช่มันเป็นสิ่งที่คุณจริงๆ สามารถ ฉันคิดว่า ดูตัวอย่างรหัสของฉันด้านล่าง จริง ๆ แล้วฉันสงสัยเกี่ยวกับสถานการณ์ที่คุณอธิบาย แต่นานมาแล้ว --- ปัญหาคลาสสิกมันจะดูเหมือน ตั้งแต่นี้ฉันไม่ได้สัมผัส bash เป็นเวลาหลายปีแล้วและฉันก็ต้องกลับมาจริงๆ ${shape} และรับคะแนน $$ ฉันทำแบบนี้เป็นการออกกำลังกายเล็กน้อย

คุณจะต้องมีสองไฟล์ทั้งสองอย่างรวมอยู่ด้านล่าง: session_driver.sh (อะนาล็อกที่ง่ายมากของ expect ) และตรรกะตัวควบคุมของคุณเองในรูปแบบสคริปต์ controller_script.sh เพื่อขับเซสชั่นของคุณ ไดรเวอร์ใช้งานได้กับทั้ง telnet (โดยใช้ไคลเอ็นต์ netcat) และ ssh ต่อไปนี้เป็นสองตัวอย่างของการเชื่อมต่อครั้งแรกในโหมด ssh (SSH=1):

NAME=root SSH=1 HOST=my-nas ./session_driver.sh controller_script.sh

สิ่งนี้จะนำคุณเข้าสู่อุปกรณ์เก็บข้อมูลที่ต่อพ่วงกับเครือข่าย my-nas ในฐานะผู้ใช้ root เพื่อความสนุกแบบสุ่มด้วย ssh อย่างไรก็ตามคุณต้องระบุรหัสผ่านด้วยตนเอง และนี่คือการเรียก telnet โดยใช้โหมด telnet เริ่มต้น:

NAME=root PWORD='123' HOST=my-nas ./session_driver.sh controller_script.sh

ที่นี่คุณระบุรหัสผ่าน '123' ด้วย PWORD ดังนั้นเซสชัน telnet จึงเป็นแบบอัตโนมัติ 100%

สคริปต์ถูกทดสอบภายใต้ Linux

session_driver.sh

#! /bin/bash
#
# BASH REMOTE SESSION DRIVER
# - for scripted telnet or rsh.
#
# Ref: http://superuser.com/questions/521716/how-to-run-scripts-within-a-telnet-session
#
USAGE=$(cat <<END
Usage: session_driver.sh CONTROLLER_SCRIPT

where CONTROLLER_SCRIPT a bash source file that defines a function named
"controller_script".

Enviroment variables must pass values as the following two examples show.

(a) Connect to telnet server, the default, via nc (netcat):

    $ HOST=mybank.com NAME=me PWORD=1234 session_driver.sh milk_account.sh

    Password PWORD can be omitted.

(b) Connect to secure shell server via ssh:

    $ SSH=1 HOST=mybank.com NAME=me session_driver.sh milk_account.sh

    Do not use PWORD in this case. If needed, you'll be prompted by ssh.

Use functions echo_stderr, read_one_line_response, an read_some_lines_response
in your CONTROLLER_SCRIPT. Adjust MULTIPLE_LINES_TIMEOUT when dealing with slow
responses.
END
)

script_name="SESSION_DRIVER"

# ARGUMENTS

if [[ -z "$1" ]] || (echo "$1" | grep -qE "^[-][-]?[h|H]"); then 
    echo "$USAGE"
    exit 1
fi

controller_script_path=$1

# OVERRIDABLE PARAMETERS

HOST=${HOST:?Specify where to connect to!}
NAME=${NAME:?Specify user name} 
PWORD=${PWORD:-}          # telnet mode only
MULTIPLE_LINES_TIMEOUT=1  # how long to wait for each line of output
                          # (in seconds)
SSH=${SSH:-0}           # use telnet by default                                       

# PLUMBING

tmpdir=$(mktemp -d)                   # secure (?) place for plumbing stuff
trap 'rm -rf "$tmpdir"; echo "$script_name: all done"' EXIT  # get rid of place
                                                              # upon termination

# We'll need a backdoor fd so that we can spew output from inside the server
# controller to the outside.
exec 3>&2     # direct fd3 to a copy of fd2 (stderr)

# We'll need an extra pipe for channeling the output of the server back into the
# server controller. A named pipe will do. That's pretty portable.
mkfifo ${tmpdir}/output


# SETUP CONNECTION COMMAND AND CONTROLLER SCRIPT

# Determine mode.
if [ "$SSH" == 1 ]; then
    cmd="ssh -t -t $HOST -l $NAME"  # -t (twice) forces tty emulation
else
    cmd="nc -t $HOST 23"
fi

# Read in the controller script.
if [[ ! -f "$controller_script_path" ]]; then
    echo "$script_name: script \"$controller_script_path\"" not found
    exit 1
fi
source "$controller_script_path"
if ! (declare -f controller_script > /dev/null); then
    echo "$script_name: script didn't define function 'controller_script'"
    exit 1
fi

# SERVER CONTROLLER AUXILIARY FUNCTIONS

# Send debugging information via backdoor pipe (fd3).
function echo_stderr () {
    echo "$1" >&3
}

# Read exactly one expected line of output and forward it to stdout.
function read_one_line_response () {
    local line
     # Eat the command line as echoed by telnet.
    read < ${tmpdir}/output 
    # Now get the response line.
    read line < ${tmpdir}/output
    echo $line | tr -d '\r'       # get rid of pesky carriage returns
} 

# Read any number of lines of output, as long as they occur sufficiently
# close (within MULTIPLE_LINES_TIMEOUT seconds); pipe all to stdout.
function read_some_lines_response () {
    local line
    read < ${tmpdir}/output 
    while read -t ${MULTIPLE_LINES_TIMEOUT} line < ${tmpdir}/output; do 
        echo $line | tr -d '\r'  
    done    
}

function password_interaction() {
    if [[ -n "$NAME" && "$SSH" == 0 ]]; then
        # Read characters up to ':'. We won't get a complete line. Hopefully
        # we'll see "login".
        while true; do
            read -d ":" line < ${tmpdir}/output; 
            (echo $line | grep "login" > /dev/null) && break;
        done
        echo "$NAME"
        read < ${tmpdir}/output
        echo "$PWORD"
        read < ${tmpdir}/output 
    else
        read_some_lines_response > /dev/null        
    fi
}

# Push out commands to server on standard output. Read the server's output from
# the pipe. And push logging information on fd3.
function controller() {

    password_interaction

    controller_script     # call the script provided as command line argument
}

# SOLDERING IT ALL TOGETHER

# The controller's standard output goes to the server as its commands. The
# server's standard output and error go to standard output. But thanks to the
# 'tee', the controller is also able to read the server's standard output and
# error through the named pipe. Note backdoor output, produced by the controller
# on fd3, goes to stderr of the pipe line by 'exec' file redirection above.
controller | ${cmd} 2>&1 | tee ${tmpdir}/output

controller_script.sh

# Sample controller script for session_driver, a bash-way of doing 'expect'
# for driving remote telnet or ssh sessions.  This script is to be sourced by
# the session_driver.sh script.

# Note our use of stuff defined in the sourcing script:
# - echo_stderr to send logging information via backdoor;
# - read_one_line_response, blocking function, to obtain an expected output 
#   line;
# - read_some_lines_response, temporarily blocking function, to obtain several 
#   lines of expected output; and
# - ${tmpdir} for temporary use.

MAX_ITERATIONS=10  # just so that we can bound the example

# MAKE LIST OF INITIAL COMMANDS FOR SERVER
cat > ${tmpdir}/myinitcommands <<- EOF
    echo hello
    DoesntWork
    pwd
EOF

function controller_script () {
    local response cmdline n
   # PLAY A LIST OF COMMANDS
    while read cmdline; do 
        echo_stderr "CONTROLLER_SCRIPT: execute: $cmdline"  
        echo "$cmdline" 
        read_some_lines_response > /dev/null
    done < ${tmpdir}/myinitcommands
    echo_stderr "CONTROLLER_SCRIPT: done initial commands"  
    # DO SILLY INTERACTION A NUMBER OF TIMES 
    # We here carefully read the one-line response to each issued command and
    # react accordingly: if the #seconds of the wall clock is even, then we
    # ask the server to give us its current directory listing.
    for ((n=0; n < $MAX_ITERATIONS; n++)); do
        # Make server invoke date function to get number of seconds in current
        # minute.
        echo_stderr "CONTROLLER_SCRIPT: execute: \"date +f %S\""   # log command
        echo "sleep 2; date +%S"                                   # do it!
        # Read one line of output. In general, one needs to be careful 
        # about how much output to read: the read is blocking!
        response=$(read_one_line_response)
        if ((${response#?} % 2  == 0)); then
            echo_stderr "CONTROLLER_SCRIPT: even: $response seconds" # log event
            echo "ls /"                          # execute on server
            read_some_lines_response > /dev/null # don't need it here             
        else
            echo_stderr "CONTROLLER_SCRIPT: odd: $response seconds" # log event
        sleep 1
        fi
    done
    echo exit # terminate remote session
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.