Under bash, you could use script
script
will produce a tty you could interact with under bash, using coproc
. This could be done without de need of expect
:
NAME
script - make typescript of terminal session
SYNOPSIS
script [options] [file]
DESCRIPTION
script makes a typescript of everything on your terminal session.
The terminal data are stored in raw form to the log file and information
about timing to another (optional) structured log file. The timing
log file is necessary to replay the session later by scriptreplay(1) and to
store additional information about the session.
Demo
coproc script -f /dev/null
Could return:
[1] 2103233
This initiate a subshel, you coul interact with,
while read -t 0 -u ${COPROC[0]};do
read -t .02 -ru ${COPROC[0]} line
echo "$line"
done
should produce something like:
Script started, output log file is 'typescript'.
user@hostname:~$
Then
echo >&${COPROC[1]} ssh user@target
while [ ! "$line" ] || [ "${line//*password*}" ];do
read -t .02 -ru ${COPROC[0]} line
echo "$line"
done
echo >&${COPROC[1]} TheStrongPasswordInClear
while [ ! "$line" ] || [ "${line//*\$*}" ];do
read -t .02 -ru ${COPROC[0]} line
echo "$line"
done
There, you could see a lot of lines like
ssh user@target
user@target's password:
Linux target 5.00.0-0-amd64 # Distro ...
issue.net content...
Last login: Sun Dec 19 12:23:37 2021 from somewhere
user@target:~$
From there, you could:
getres() {
while read -t 0 -u ${COPROC[0]};do
read -t .02 -ru ${COPROC[0]} line
echo "$line"
done
}
echo >&${COPROC[1]} uptime
getres
uptime
12:38:38 up 21 days, 3:52, 122 users, load average: 3.20, 2.19, 1.59
And finaly
echo >&${COPROC[1]} exit
getres
exit
logout
Connection to target closed.
Full executable bash script
This run under bash 5.1.4(1)-release
, on GNU/Debian Linux 11.2
:
#!/bin/bash
line='' Debug=false
exp1() { # Collect input by bytes, until expected string (1st arg)
local char attended="*${1}"
line=
IFS= read -d '' -ru "${COPROC[0]}" -t 2 -n 1 line
while IFS= read -d '' -ru "${COPROC[0]}" -t .02 -n 1 char;do
line+="$char"
case "$line" in
*$1 ) $Debug && echo "GOOD ${line@A} match ${attended@A}"
return 0;;
esac
done
$Debug && echo "BAD: ${line@A}"
return 1
}
expect() { # expect <Expected String after> <Command> [switches] [args]
local expectStr="$1" maxErr=5
shift
[ "$1" ] && echo >&"${COPROC[1]}" "$@"
while ! exp1 "${expectStr}" && ((maxErr--));do sleep .2;done
}
getAns() { # getAns <ResultVar> <Command> [switches] [args]
local -n res=$1
res=''
shift
local req="$*" maxErr=5
echo >&"${COPROC[1]}" "$req"
exp1 "$req"$'\r\n'
while ! exp1 "$ " && ((maxErr--));do res+="$line" ;sleep .2 ;done
res+="${line%$'\r\n'*}"
}
read -rp target:\ target
read -rsp password:\ pass
echo "${pass//?/*}"
coproc TERM=none script -f /dev/null
IFS= read -ru "${COPROC[0]}" line &&
$Debug && echo "1 >>> $line <<<"
expect '$ '
expect 'password: ' ssh "$target"
expect '$ ' "$pass"
getAns ut uptime
# shellcheck disable=SC2154 # referenced but not assigned (ut ??)
echo "${ut@A}"
expect '$ ' exit
Run sample:
target: user@target
password: ************
ut=' 11:06:20 up 5 days, 2:19, 22 users, load average: 0.74, 1.13, 1.27'
You may found this script on my site: expectScr.sh, or expectScr.sh.txt, ready to be sourced.