나는 지금까지 달성한 결과로 인해 내 질문을 구체화하고 있습니다.
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 2]
if {[llength $argv] == 0} {
send_user "Usage: scriptname username \'password\' hostname\n"
exit 1
}
send_user "\n#####\n# $hostname\n#####\n"
spawn ssh -q -o StrictHostKeyChecking=no $username@$hostname
expect {
timeout { send_user "\nFailed to get password prompt\n"; exit 1 }
eof { send_user "\nSSH failure for $hostname\n"; exit 1 }
"Password: "
}
send "$password\r"
expect {
timeout { send_user "\nLogin failed. Password incorrect.\n"; exit 1}
"{severname:mike} "
}
send "ls -lrt\n"
expect {
"{severname:mike} " {
send "uname\n"
}
}
expect {
"{severname:mike} " }
send "exit\r"
close
내 말이 맞기를 바라지만 명령이 ls, ls -lrt 등과 같은 명령 목록인 로컬로 기록된 명령의 출력 오류 로그 및 성공 로그를 어떻게 얻을 수 있습니까?
게다가 내가 이렇게 말할 때:
spawn ssh -q -o StrictHostKeyChecking=no $username@$hostname {ls -lrt;df -h}
로그인하여 실행 ls -lrt;df -h
하지만 디버그 옵션을 사용하면 오류가 발생합니다. 명령이 ssh 범위 내에서 실행되었기 때문에 연결이 닫혔을 수 있습니다.
[root@testgfs2 final]# ./workingscript.exp mike bar01 10.38.164.103
#####
# 10.38.164.103
#####
spawn ssh -q -o StrictHostKeyChecking=no [email protected] ls -lrt
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {19901}
expect: does "" (spawn_id exp6) match glob pattern "Password: "? no
Password:
expect: does "Password: " (spawn_id exp6) match glob pattern "Password: "? yes
expect: set expect_out(0,string) "Password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Password: "
send: sending "bar01\r" to { exp6 }
expect: does "" (spawn_id exp6) match glob pattern "{severname:mike} "? no
expect: does "\r\n" (spawn_id exp6) match glob pattern "{severname:mike} "? no
total 6
-rw-r--r-- 1 mike other 136 Feb 26 08:39 local.cshrc
-rw-r--r-- 1 mike other 157 Feb 26 08:39 local.login
-rw-r--r-- 1 mike other 174 Feb 26 08:39 local.profile
expect: does "\r\ntotal 6\r\n-rw-r--r-- 1 mike other 136 Feb 26 08:39 local.cshrc\r\n-rw-r--r-- 1 mike other 157 Feb 26 08:39 local.login\r\n-rw-r--r-- 1 mike other 174 Feb 26 08:39 local.profile\r\n" (spawn_id exp6) match glob pattern "{severname:mike} "? no
expect: read eof
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\r\ntotal 6\r\n-rw-r--r-- 1 mike other 136 Feb 26 08:39 local.cshrc\r\n-rw-r--r-- 1 mike other 157 Feb 26 08:39 local.login\r\n-rw-r--r-- 1 mike other 174 Feb 26 08:39 local.profile\r\n"
write() failed to write anything - will sleep(1) and retry...
send: sending "ls -lrt\n" to { exp6 send: spawn id exp6 not open
while executing
"send "ls -lrt\n""
(file "./workingscript.exp" line 30)
명령 변수에는 다음과 같이 세미콜론으로 구분된 명령 목록이 포함되어 있습니다.
command 1; command 2;command 3(=$command)
Expect 스크립트에서 하나씩 수행하는 방법을 모르므로 ssh 범위에 명령을 넣는 대신 다음을 수행할 수 있습니다.
spawn ssh -q -o StrictHostKeyChecking=no $username@$hostname
IFS=';'
for i in $command
do
expect {
"{severname:mike} " {
send "$i\n"
} 2>> errorlog 1>> succeslog
}
done
나는 단지 내가 하려는 일에 대한 아이디어를 제공하기 위해 유닉스 구문과 Expect 구문의 조합을 사용하고 있을 뿐입니다.
답변1
Expect의 상호 작용 모델에는 stdout 및 stderr 스트림 분리가 포함되지 않습니다. 프로세스를 생성할 때 사용자가 터미널에서 보는 것과 거의 동일하게 동작하는 새로운 의사 TTY를 생성하지만 사용자는 둘 사이의 차이점을 구분하지 못하는 경우가 많습니다. 시도 해봐:
$ echo "This is stdout"
This is stdout
$ echo "This is stderr" 1>&2
This is stderr
하지 마세요무엇차이점을 표시하기 위해 Expect는 이를 구별할 방법이 없습니다(명령줄의 사용자와 마찬가지로). 그러므로 Expect는 아마도 당신이 해야 할 일에 대한 잘못된 도구일 것입니다.
이제 이것이 왜 필요한지 정확히 알지 못하면 대안을 찾기가 어렵습니다. 필요한 경우 단일 ssh 명령을 사용하여 이를 수행할 수 있는 것처럼 보입니다.
ssh -q -o StrictHostKeyChecking=no $username@$hostname "ls -lrt; df -h" 1>>successlog 2>>errorlog
하위 프로세스 생성 및 stdout 및 stderr 가져오기를 기본적으로 지원하는 다른 스크립팅 언어의 경우 Python 및 해당 하위 프로세스 모듈을 사용해 보세요.
import shlex
from subprocess import Popen, PIPE
cmd = Popen(shlex.split('ssh -q -o StrictHostKeyChecking=no $username@$hostname "ls -lrt; df -h"'), stdout=PIPE, stderr=PIPE)
cmd.wait() # Wait for the command to complete
success_output = cmd.stdout
error_output = cmd.stderr
하지만 만약 당신이 정말로진짜Expect에서 이 작업을 수행하려면 마지막 프로세스의 종료 값을 확인하고 해당 값이 0이 아닌 경우 오류 로그 파일에 기록하는 것이 가장 좋은 방법이라고 생각합니다. 비슷한 예는 다음과 같습니다.
spawn ssh -q -o StrictHostKeyChecking=no $username@$hostname
# Receive password prompt and send the password here...
expect {
-ex $prompt { send "ls -lrt\r" }
timeout {
send_user "Everything is terrible forever.\n"
exit 1
}
}
expect {
-ex $prompt {
set output $expect_out(buffer)
send {echo RETVAL::$?::}
send "\r"
}
timeout {
send_user "Everything is terrible forever.\n"
exit 1
}
}
expect {
-ex {RETVAL::0::} {
set fp [open successlog a]
puts $fp $output
close $fp
}
-re {RETVAL::[1-9][0-9]*::} {
set fp [open errorlog a]
puts $fp $output
close $fp
}
timeout {
send_user "Everything is terrible forever.\n"
exit 1
}
}