Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
####### # # E-scripts on Expect. # # Note 1: use the eev command (defined in eev.el) and the # ee alias (in my .zshrc) to execute parts of this file. # Executing this file as a whole makes no sense. # An introduction to eev can be found here: # # (find-eev-quick-intro) # http://angg.twu.net/eev-intros/find-eev-quick-intro.html # # Note 2: be VERY careful and make sure you understand what # you're doing. # # Note 3: If you use a shell other than zsh things like |& # and the for loops may not work. # # Note 4: I always run as root. # # Note 5: some parts are too old and don't work anymore. Some # never worked. # # Note 6: the definitions for the find-xxxfile commands are on my # .emacs. # # Note 7: if you see a strange command check my .zshrc -- it may # be defined there as a function or an alias. # # Note 8: the sections without dates are always older than the # sections with dates. # # This file is at <http://angg.twu.net/e/expect.e> # or at <http://angg.twu.net/e/expect.e.html>. # See also <http://angg.twu.net/emacs.html>, # <http://angg.twu.net/.emacs[.html]>, # <http://angg.twu.net/.zshrc[.html]>, # <http://angg.twu.net/escripts.html>, # and <http://angg.twu.net/>. # ####### # «.expect.info» (to "expect.info") # «.represent-interact» (to "represent-interact") # «.expect.nist.gov» (to "expect.nist.gov") # «.cotse» (to "cotse") # «.debugger» (to "debugger") # «.switching_versions» (to "switching_versions") # «.modem_interact» (to "modem_interact") # «.splitting_output_0» (to "splitting_output_0") # «.splitting_output_1» (to "splitting_output_1") # «.splitting_input_0» (to "splitting_input_0") # «.splitting_input_1» (to "splitting_input_1") # «.mini-kibitz» (to "mini-kibitz") # «.interact-re-problem» (to "interact-re-problem") # «.mini-autoexpect» (to "mini-autoexpect") # «.expect_arrays» (to "expect_arrays") # «.dejagnu» (to "dejagnu") # «.regress.ps-listings» (to "regress.ps-listings") # «.modem» (to "modem") # «.curses» (to "curses") # «.expect_bugs_potato» (to "expect_bugs_potato") # «.inetd_logger0» (to "inetd_logger0") # «.stty» (to "stty") # «.shell-utils» (to "shell-utils") # «.input-from-fifo» (to "input-from-fifo") # «.passwords» (to "passwords") # «.autopasswd» (to "autopasswd") # «.noncanonical-mode» (to "noncanonical-mode") # «.getconf-pipe-buf» (to "getconf-pipe-buf") (find-fline "/usr/doc/expect5.24/FAQ.gz") (find-fline "/usr/doc/expect5.24/examples/") ##### # # Installing the info/texinfo version of the Expect manpage # 2001apr17 # ##### # «expect.info» (to ".expect.info") # (find-es "texinfo") # (find-angg "EXPECT/expect.texi") #* cd ~/EXPECT/ rm -v expect.info* makeinfo expect.texi gzip -9v expect.info* laf expect.* install-info --remove expect echo $? rm -v /usr/share/info/expect.info* cd ~/EXPECT/ cp -v expect.info* /usr/share/info/ install-info \ --section Programming Programming \ --description='Expect 5.31.8.' \ /usr/share/info/expect.info.gz echo $? # (find-node "(dir)Top" "expect") # (find-node "(expect)Top") #* cd ~/EXPECT/ anonftp angg.twu.net 'cd /home2/edrx/info/' 'mput expect.info*' 'quit' #* ##### # # Representing an interaction with Expect # 2001jul16 # ##### # «represent-interact» (to ".represent-interact") We'll treat only the case where there's exactly one spawned process. Atomic actions: P<------E c expect sends a char "c" to the process P------>E c the process sends a char to expect E<------U c the user sends a char to expect E------>U c expect sends a char to the user (n secs) n seconds pass without any chars There are several other kinds of actions, like sending or receiving signals, or the process closing, but I don't want to discuss them now. Also, the communication happens through terminals, and either side of a terminal may change some of its settings; and, as each terminal can do some buffering and char translation the "real" arrows would be P<--T c P-->T c T<--E c T-->E c E<--T c E-->T c T<--U c T-->U c I don't understand terminals very well, but I know that they have lots of settings and are quite complex... there are some notes at the link below. # (find-es "modem" "modem_tty_bits") String actions: P<------E str expect sends a string "str" to the process P------>E str the process sends a string to expect E<------U str the user sends a string to expect E------>U str expect sends a string to the user Note that a string action can correspond to several different sequences of character actions through terminals, but we don't care which... for example, both T<--E "a" P<--T "a" T<--E "b" P<--T "b" and T<--E "a" T<--E "b" P<--T "a" P<--T "b" can be written as string actions as P<------E "ab". Also there are string actions with translation: P<------E strp<-stre expect sends stre and P receives strp P------>E strp->stre P sends strp and expects receives stre E<------U stre<-stru the user sends stru and E receives stre E------>U stre->stru expect sends stre and U receives stru and communications between two agents in which we only care for one side, typically because the other is just echoing, or answering in a very standard & boring way: p<------E \ stre1 expect sends stre1 and p\----->E / stre2 receives stre2 e<------U \ stru1 the user sends stru1 and e\----->U / stru2 receives stru2 P------>e \ strp1 the process sends strp1 and P<-----/e / strp2 receives back strp2 I'm using lowercases in the name of one the agents of these types of commutications to stress that its side of the communication has to be inferred from the other, as its strings are not being shown explicitly; and, of course, there are many possible ways to expand these actions into "more atomic" actions. For example: p<------E \ "ab" p\----->E / "cd" can be P<------E "ab" P------>E "cd", or P------>E "c" P<------E "ab" P------>E "d", or several others, maybe even with pauses and terminal translation. Extending this idea we may have things like p<------e<------U \ stru1 p\----->e------>U / stru2, that is typical of when we're using the "interact" command, p<------E \ stre p\----->e------>U / stru, for a situation where expect sends a string (after a timeout, say) and we are only interested in what the users gets as a consequence of that. ##### # # Don Libes' site: expect.nist.gov # 2001jul16 # ##### # «expect.nist.gov» (to ".expect.nist.gov") # (find-shttpw3 "expect.nist.gov/") # (find-shttpfile "expect.nist.gov/") ##### # # Expect texts at COTSE # 2001jul16 # ##### # «cotse» (to ".cotse") # (find-shttpw3 "members.cotse.com/dlf/man/expect/") # (find-shttpfile "members.cotse.com/dlf/man/expect/") psner http://members.cotse.com/dlf/man/expect/ -A htm,html,txt,css -nc -np # Weird, netscape can't display these pages... w3m $FLH/snarf/http/members.cotse.com/dlf/man/expect/ w3m $FLH/snarf/http/members.cotse.com/dlf/man/expect/index.htm w3m $FLH/snarf/http/members.cotse.com/dlf/man/expect/bulletproof1.htm ##### # # Using Expect's internal Tcl debugger # 2000dec25 # ##### # «debugger» (to ".debugger") # (find-fline "~/tmp/EXPECT/") #* cat > $EEG <<'---' h exit --- eeg expect -D 1 #* cd /tmp/ cat > debug-text.exp <<'---' set b 1 proc p4 {x} { return [ expr 5+[expr 1+$x]] } set z [ expr 1+[expr 2+[p4 $b]] ] proc p3 {} { set m 0 } proc p2 {} { set c 4 p3 set d 5 } proc p1 {} { set a 2 p2 set a 3 set a 5 } p1 set k 7 p1 --- cat > $EEG <<'---' w info exists b n w info exists b n w s w s info locals puts $x info level s w info exists b u w info exists b set b puts $b concat {} # Bye... exit --- clear; eeg expect -D 1 debug-text.exp #* ##### # # switching between the two expect versions in potato # 2000oct01 # ##### # «switching_versions» (to ".switching_versions") apti expect5.31-dev tk8.2-dev # or apti expect5.24-dev tk8.0-dev # (find-status "expect5.31") # (find-vldifile "expect5.31.list") # (find-fline "/usr/doc/expect5.31/") # (find-status "expect5.31-dev") # (find-vldifile "expect5.31-dev.list") # (find-fline "/usr/doc/expect5.31-dev/") # apti expectk5.31 # (find-status "expectk5.31") # (find-vldifile "expectk5.31.list") # (find-fline "/usr/doc/expectk5.31/") cd /tmp/ /usr/share/doc/expect5.31/examples/autoexpect tcsh #* cp -a /usr/share/doc/expect5.31/examples/autoexpect /tmp/autoex # (find-fline "/tmp/autoex") #* ##### # # stty (in expect and in shell-utils) # 2001jan03 # ##### # «stty» (to ".stty") # (find-man "1 stty") # (to "expect5.31-src") # (find-exptag "Exp_SttyCmd") # (find-expfile "exp_tty.c" "if any unknown args") # (find-es "modem" "modem_tty_bits") # (find-node "(coreutils)stty invocation") # «shell-utils» (to ".shell-utils") #* pdsc $SDEBIAN/dists/potato/main/source/base/shellutils_2.0-7.dsc cd /usr/src/shellutils-2.0/ find * | sort > .files find * -name '*.[ch]' | sort > .files.ch etags $(<.files.ch) #* cd /usr/src/shellutils-2.0/ debian/rules binary |& tee odrb # (find-shufile "odrb") cd /usr/src/shellutils-2.0/builddir/src/ gcc -DLOCALEDIR=\"/usr/share/locale\" -DHAVE_CONFIG_H \ -I.. -I../../src -I../../lib -I../intl \ -E ../../src/stty.c > ../../src/stty.E # (find-shufile "src/stty.E") # (find-shutag "display_settings") # (find-shutag "display_recoverable") # (find-shufile "src/stty.E" "\ndisplay_recoverable") # Weird: for the kernel NCCS=19, but from the outside NCCS=32... # (find-k22file "include/asm-i386/termios.h") # (find-k22file "include/asm-i386/termbits.h") # (find-k22file "include/asm-i386/ioctls.h") # (find-k22file "drivers/char/tty_ioctl.c" "NCCS") # (find-fline "/usr/include/bits/termios.h") # (find-fline "/usr/include/termios.h") #* cd /usr/src/shellutils-2.0/ cd tests/stty/ VERBOSE=yes basic-1 VERBOSE=yes row-col-1 #* # (find-shufile "") # (find-shufile "tests/stty/") # (find-shunode "stty invocation") # (find-shufile "src/stty.c") stty -a stty -g stty -g | awk -F : '{print NF}' # The next step is to learn how to simulate that using stty from Expect... # (find-es "modem" "modem_tty_bits") #* ##### # # splitting output # 2001jan13 # ##### # «splitting_output_0» (to ".splitting_output_0") # (find-fline "~/EXPECT/MAN/TXT/spawn") # (find-fline "~/EXPECT/MAN/TXT/interact") #* expect -c ' spawn -open [open /tmp/o w] puts $spawn_id ' #* expect -c ' spawn -open [set out_file [open /tmp/o w]] set out_spid $spawn_id spawn cat interact -output "$spawn_id $out_spid" timeout 5 return close $out_file puts "\n==> [exec tr "\004\012\015" DJM < /tmp/o]\n" ' #* # «splitting_output_1» (to ".splitting_output_1") # (find-expcommand "spawn" "user_spawn_id") # (find-expcommand "spawn" "error_spawn_id") # (find-expcommand "spawn" "tty_spawn_id") # (find-expcommand "spawn" "-open") # (find-expcommand "interact" "-input and -output") # (find-angg ".zshrc" "save-input") echo "line1\nline2\n\004" > $EEG eeg expect -c ' set idu $user_spawn_id spawn -open [set fid1 [open /tmp/out1 w]]; set id1 $spawn_id spawn -open [set fid2 [open /tmp/out2 w]]; set id2 $spawn_id spawn cat set idp $spawn_id interact { -input $idu -output $idp -output $id1 -input $idp -output $idu -output $id2 timeout 5 return } close $fid1 close $fid2 puts "" puts "==> [exec tr "\004\012\015" DJM < /tmp/out1]" puts "==> [exec tr "\004\012\015" DJM < /tmp/out2]" ' #* ##### # # splitting input # 2001jan13 # ##### # «splitting_input_0» (to ".splitting_input_0") # (find-node "(libc)Pipes and FIFOs") # (find-node "(fileutils)mkfifo invocation") # I want to let an "interact" take input from a fifo, as if the fifo # was a kibitzed keyboard; the problem is that a fifo closes when the # writing process closes... #* rm -v /tmp/fifo mkfifo /tmp/fifo (sleep 1; echo Hello > /tmp/fifo; sleep 1) & cat < /tmp/fifo #* rm -v /tmp/fifo mkfifo /tmp/fifo (sleep 2; echo Hello > /tmp/fifo; sleep 4) & expect -c ' spawn cat /tmp/fifo interact { timeout 5 {send_user "Timed out\n"; return} -o eof {send_user "Got an eof\n"; return} } puts "Interact ended" ' #* # Setting spawn_id inside a proc does not change its global value # (unless we declare it as global, of course): expect -c ' spawn cat; set catpid $spawn_id proc s {} {global lspid; spawn ls; set lspid $spawn_id} s puts "$catpid $lspid $spawn_id" ' #* # «splitting_input_1» (to ".splitting_input_1") # (to "splitting_output_1") rm -v /tmp/fifo mkfifo /tmp/fifo ( sleep 1; echo -ne 'Hello\r' > /tmp/fifo sleep 1; echo -ne 'Again!\r' > /tmp/fifo sleep 3 ) & expect -c ' proc openfifo {} {spawn -noecho cat /tmp/fifo; return $spawn_id} set idu $user_spawn_id spawn cat set idp $spawn_id while 1 { set idf [openfifo] interact { -input $idp eof break -output $idu -input $idu eof break -output $idp -input $idf eof return -output $idp timeout 2 break } } ' #* # (find-node "(screen)Screen Command" "`C-a c'") # (find-node "(screen)Split" "`C-a S'") # (find-node "(screen)Focus" "`C-a Tab'") ^ac ##### # # a problem with interact -re # 2000jan17 # ##### # «interact-re-problem» (to ".interact-re-problem") # (find-expmanfile "expect") # (find-expmanfile "interact") # (find-expfile "exp_inter.c") # (find-exptag "Exp_InteractObjCmd") # (find-expfile "exp_inter.c" "exp_one_arg_braced") # (find-exptag "exp_one_arg_braced") # (find-exptag "exp_eval_with_one_arg") # Ahaa - we need a \n before the first non-blank... #* # echo '\a\r\f%^\n\a' > /tmp/o echo '...%^...' > /tmp/o expect -c ' proc gotit {} {send_user !!!} spawn cat /tmp/o; interact -o % gotit spawn cat /tmp/o; interact -o -re % gotit spawn cat /tmp/o; interact -o -re {[%^]} gotit spawn cat /tmp/o; interact { -o % gotit } spawn cat /tmp/o; interact { -o {%} gotit } spawn cat /tmp/o; interact { -o -re % gotit } spawn cat /tmp/o; interact -nobrace -o % gotit spawn cat /tmp/o; interact -nobrace -o {%} gotit spawn cat /tmp/o; interact -nobrace -o -re % gotit ' #* # (find-es "perl" "eval_in_regsub") echo -ne '\b\e\f\n\r\t\v' > /tmp/o expect -c 'proc gotit {} {send_user !!!} spawn cat /tmp/o; interact -o -re {[\r\n]} gotit ' echo -ne 'foo\nbar\n' > /tmp/o expect -c 'proc gotit {} {send_user !!!} spawn cat /tmp/o; interact -o -re {[\r\n]} gotit ' echo -ne 'foo\n%%> bar\n%%> ' > /tmp/o expect -c 'proc gotit {} {send_user !!!} spawn cat /tmp/o; interact -o -nobuffer -re {[\r\n]%+> } gotit spawn cat /tmp/o; interact { -o -nobuffer -re {[\r\n]%+> } gotit } set prompt {[\r\n]%+> } spawn cat /tmp/o; interact { -o -nobuffer -re $prompt gotit } ' | tee ~/o | tr \\r \\n # (find-file-literally "~/o") # (find-enode "Coding Systems") # (find-enode "Visiting") #* # The problem is more subtle set prompt {[\r\n]%+> } set prompt "\[\r\n\]%+> " set prompt "\n%+> " set prompt {..%+> } set prompt {..\%+> } # (progn (find-fline "/tmp/o") (wrap 0)) # (progn (find-file-literally "/tmp/o") (wrap 0)) # (find-angg "EXPECT/eeg") # (find-fline "~/EXPECT/eeg2") # (find-expfile "exp_inter.c" "spawn id %s sent") # (find-expfile "exp_log.c" "static char *\nexpPrintifyReal(s)") # (find-expmanfile "exp_internal") ##### # # mini-kibitz # 2000jan13 # ##### # «mini-kibitz» (to ".mini-kibitz") # (find-status "expect5.24") # (find-vldifile "expect5.24.list") # (find-fline "/usr/doc/expect5.24/") cp -v /usr/share/doc/expect5.24/examples/kibitz ~/tmp/kibitz # (find-fline "~/tmp/kibitz") # (find-fline "~/EXPECT/MAN/TXT/") # (find-fline "~/EXPECT/MAN/TXT/spawn") ##### # # A minimal "autoexpect" # 2001jan21 # ##### # «mini-autoexpect» (to ".mini-autoexpect") # (code-c-d "expex" "/usr/doc/expect5.31/examples/") # (find-expexfile "autoexpect") # (find-expexfile "autoexpect" "eval interact") # (find-expexfile "autoexpect" "proc input") # (find-expexfile "autoexpect" "proc output") # (find-expexfile "autoexpect" "proc expand") #* cat > $EEG <<'---' 1 + 2 e(1) l(3)/l(2) quit --- cat > /tmp/ae.exp <<'---' set buf {} set mode none set pairs {} proc newmode {newmode newbuf} { global buf mode pairs if {$mode!="none"} { lappend pairs $mode $buf } set mode $newmode set buf $newbuf } proc gotstr {from str} { global buf mode pairs if {$from==$mode} { append buf $str } else { newmode $from $str } } interact { -nobuffer -re .+ { gotstr i $interact_out(0,string) } -o -nobuffer -re .+ { gotstr o $interact_out(0,string) } } --- ~/bin/eeg \ expect -c ' source $env(HOME)/TCL/inc.tcl ;# (find-angg "TCL/inc.tcl") spawn bc -l source /tmp/ae.exp writefile /tmp/io $pairs ' # (find-fline "/tmp/io") #* ##### # # inspecting expect's arrays # 2000oct02 # ##### # «expect_arrays» (to ".expect_arrays") # (find-fline "/usr/lib/tcl8.0/parray.tcl") #* expect -c ' proc puts {channel str} { send_user $str\n } proc buf {} { global interact_out; return $interact_out(0,string) } spawn tcsh interact { -re . { send_user "key\n"; parray interact_out } -o -re . { send_user "prog\n"; parray interact_out } eof { exit } } ' #* ##### # # Expect variables # ##### # (eeman "expect" "expect_out") # (eeman "expect" 651) # (eeman "expect" "any_spawn_id") # (eeman "expect" "interact_out") # (eeman "expect" "send_slow") # (eeman "expect" "send_human") # (eeman "expect" 1624) ###### # # kibitz # ###### # (find-vldifile "expect5.24.list") # (find-fline "/usr/doc/expect5.24/examples/") cd /usr/doc/expect5.24/examples/ man2t kibitz.1 man2t /usr/doc/expect5.24/examples/kibitz.1 gzip -c9 < /usr/doc/expect5.24/examples/kibitz.1 > /usr/man/man1/kibitz.1.gz ln -sf /usr/doc/expect5.24/examples/kibitz /usr/bin/kibitz # (find-fline "/usr/doc/xterm/") cd /usr/doc/expect5.24/examples/ kibitz alex /usr/doc/expect5.24/examples/kibitz alex # (find-fline "/usr/doc/expect5.24/examples/kibitz") echo 'exec echo Helloooo! > /dev/tty5' | tclsh - pdsc /debian/dists/slink/main/source/utils/bsdmainutils_4.4.0.1.dsc # (find-fline "/usr/src/bsdmainutils-4.4.0.1/") # (find-fline "/usr/src/bsdmainutils-4.4.0.1/write.c") # (find-fline "/usr/src/bsdmainutils-4.4.0.1/mesg.c") tty # (eeman "1 tty") # (eeman "4 tty") man -a console man -a chvt man -a deallocvt usr/bin/mesg base/sysvinit ###### # # kibitz # ###### cd ~/EXPECT/ grep -v '^[ ]*#' mykibitz > mykibitz0 # (find-fline "~/EXPECT/mykibitz") # (find-fline "~/EXPECT/mykibitz0") # (eeman "expect" 1614) # (find-fline "~/.zshrc" "kibitz") ###### # # On doing my own kibitz # ###### # (eeman "expect" 736) # (find-fline "~/EXPECT/mykibitz") puts $argv if {$argv=="server"} { } puts "I'm the server." exec rm -fv /tmp/toserver catch [exec mkfifo /tmp/toserver] puts "pipefd: [set pipefd [open /tmp/toserver {RDONLY NONBLOCK}]]" puts "spawn pipe: [spawn -open $pipefd]" puts "pipesid: [set pipesid $spawn_id]" puts "" puts "shellpid: [set shellpid [spawn $env(SHELL)]]" puts "shellsid: [set shellsid $spawn_id]" set timeout -1 expect { -i $pipesid -re .+ { puts hello!} } puts fuck set spawn_id $shellsid expect { -re .+ { send_user -raw $expect_out(buffer) exp_continue } -i $user_spawn_id -re .+ { send $expect_out(buffer) exp_continue } } puts "Server happy! Bye." -i $pipesid -re .+ { send $expect_out(buffer) exp_continue } expect { timeout {send "abc \177d"; continue -expect} -re .+ {send_user -raw $expect_out(buffer); continue -expect} -i $user_spawn_id -re .+ {send $expect_out(buffer); continue -expect} } # interact: # (eeman "expect" 972) # (find-expfile "") # (find-expfile "exp_inter.c") # (find-expfile "exp_inter.c" "Exp_InteractCmd") # (find-fline "$S/http/expect.nist.gov/scripts/") # (find-fline "$S/http/expect.nist.gov/scripts/noidle") -re ".*" { puts "pipe input!" } puts [set z [spawn zsh]] puts $spawn_id set spawn_id $z interact "~~" { puts "tildes!" } interact { -output $shid "~~" { puts "tildes!" } -input $inid -re ".*" { puts "oba!" } } else { puts [set fout [open /tmp/toserver {WRONLY NONBLOCK}]] puts [set fout [open /tmp/fromserver {WRONLY NONBLOCK}]] puts "Client happy! Bye." } catch [exec mkfifo /tmp/fromserver] puts [exec rm -fv /tmp/fromserver] puts [exec ls -laF /tmp] # Esse fica bloqueado até o cliente abrir a conexão: # puts [set fout [open /tmp/fromserver {WRONLY}]] set idfs [open /tmp/fromserver r] puts "$idsh $idfs $idts" ##### # # expect using tcl/tk 7.6 # ##### pdsc /debian/dists/slink/main/source/interpreters/expect_5.28.1-1.dsc # (find-expfile "exp_main_exp.c") # (find-expfile "exp_main_sub.c") # (find-expfile "exp_main_tk.c") # (find-expfile "Makefile.in" "expectk: ") cd /usr/src/expect-5.28.1/ debian/rules binary |& tee odrb # (find-expfile "odrb") # (find-expfile "exp_command.c" 1216) # (find-expfile "exp_command.c" 3181) # (find-expfile "exp_command.E" "setpgrp(0,0)") # C-c C-p c-backward-conditional # C-c C-n c-forward-conditional lynx http://www.distributedobjects.com/portfolio/archives/patterns/discussion/msg03277.html gcc -D_REENTRANT -E \ -I. \ -I/usr/include/tcl8.0-int/generic \ -I/usr/include/tk8.0-int/generic \ -I/usr/X11R6/include \ -DEXP_VERSION=\"5.28.1\" \ -DSCRIPTDIR=\"/usr/lib/expect5.28\" \ -DEXECSCRIPTDIR=\"/usr/lib/expect5.28\" \ -DTCL_DEBUGGER \ -DDFLT_STTY="\"sane\"" exp_command.c > exp_command.E # (find-expfile "debian/rules") # (find-expfile "odrb") # (find-expfile "configure.in") # (find-expfile "configure") # (find-expfile "Dbgconfig.in") # (find-expfile "Dbgconfigure") Pgrep 'm/ckage: (expect5.24|tcl|tk[48])/' apti tcl7.6-dev tk4.2-dev # The following packages will be REMOVED: # expect5.24-dev tk8.0-dev tcl8.0-dev # The following NEW packages will be installed: # tk4.2-dev tcl7.6-dev ###### # # Tuba on Tuba # ###### # (find-fline "/usr/lib/tcl8.0/") # (find-fline "/usr/lib/tk8.0/") # (find-vldifile "tk8.0.list") # (find-tubafile "") # (find-tubafile "tuba" ".tubarc") # (find-tubafile "tuba" "proc main ") # (find-tubafile "tuba_lib.tcl") ##### # # dejagnu # 2001jan20 # ##### # «dejagnu» (to ".dejagnu") # (find-es "gdb" "gdb-source") # (find-status "dejagnu") # (find-vldifile "dejagnu.list") # (find-fline "/usr/doc/dejagnu/") # (find-node "(dejagnu)Top") # (find-node "(dejagnu)Running Tests") # (find-node "(dejagnu)Invoking runtest") # (find-fline "/usr/bin/runtest") # (eeman "1 runtest") # (find-fline "/usr/share/dejagnu/") #* # (find-node "(dejagnu)Sample Test") cd /tmp/ cat > gdb.echo.exp <<'---' # send a string to the GDB stdin: send "echo Hello world!\n" # inspect the GDB stdout for the correct reply, # and determine whether the test passes or fails: expect { -re "Hello world.*$prompt $" { pass "Echo test" } -re "$prompt $" { fail "Echo test" } timeout { fail "(timeout) Echo test" } } --- runtest --tool_exec gdb gdb.echo.exp #* Uma coisa que eu não tou entendendo. O expect sempre deixa todos os processinhos rodando, ou ele pode suspendê-los, como o shell? Aliás, o sigsusp é não-trapável? Qdz, um processo percebe quando é suspendido? Ele percebe quando é "dessuspendido", né? Ele precisa disso pra redesenhar a tela, como o emacs. Se os processos não são suspendidos então não tem sentido falar em job control, a não ser que o job control só determine o que vai parar na tela e que processo recebe o que o usuário tecla. O expect sabe mandar signals para os filhinhos? Como? Uma ferramenta que poderia deixar bem mais claro como é que o expect funciona: como eu acho que o cerne do expect é um enorme "select", algo que mostrasse tudo que entra e que sai nesse select. # (find-vldifile "tcl8.0-dev.list") # (find-fline "/usr/doc/tcl8.0-dev/") # (eeman "3tcl tclvars") set tcl_traceCompile 2 for i in $(grep /usr/man/man /var/lib/dpkg/info/tcl8.0-dev.list); do echo $i; zcat $i | grep auto_path done any_spawn_id error_spawn_id tty_spawn_id user_spawn_id exp_exec_library exp_library expect_library spawn_id spawn_out timeout ##### # # expect variables # ##### puts [info vars] puts [spawn cat] foreach var { any_spawn_id error_spawn_id tty_spawn_id user_spawn_id exp_exec_library exp_library expect_library spawn_id timeout } { catch { puts "$var: [set $var]" } } puts "spawn_out(): [array get spawn_out]" diald exmh dejagnu ###### # # http://expect.nist.gov/scripts/ # ###### # (find-fline "$S/http/expect.nist.gov/scripts/") # (find-fline "~/EXPECT/dialer") ###### # # http://expect.nist.gov/doc/ # ###### # (find-fline "$S/http/expect.nist.gov/doc/") # (find-fline "$S/http/expect.nist.gov/doc/regress-talk.ps" "csh") cd $S/http/expect.nist.gov/doc/ pstotext regress.ps > /tmp/regress.txt pstotext -landscape regress-talk.ps > /tmp/regress-talk.txt pstotext scripts.ps > /tmp/scripts.txt # (find-fline "/tmp/") ##### # # http://expect.nist.gov/doc/regress.ps: listings # ##### # «regress.ps-listings» (to ".regress.ps-listings") set password [lindex $argv 2] spawn passwd [lindex $argv 1] expect "password:" send "$password\r" expect "password:" send "$password\r" expect eof # Listing 1: Non-interactive passwd script. First argument is # username. Second argument is new password. ################ expect_after { eof {exit [expr 10+$question]} timeout {exit [expr 20+$question]} } set question 0 proc test {args} { uplevel {incr question} eval [concat expect $args] } spawn passwd [lindex $argv 1] test { "No such user" {exit 1} "New password:" } send "[lindex $argv 2]\r" test { "Password too long" {exit 2} "Password too short" {exit 3} "Retype new password:" } send "[lindex $argv 3]\r" test { "Mismatch - password unchanged" {exit 4} "^\r\n$" } test { "*" {exit 5} eof } # Listing 2: Non-interactive passwd script with various tests for # behavior at boundary conditions. ################ passwd.exp bogus - - 1 passwd.exp fred abledabl abledabl 0 passwd.exp fred abcdefghijklm - 3 passwd.exp fred abc - 2 passwd.exp fred foobar bar 4 passwd.exp fred ^C - 11 # Listing 3: Example data file for testing passwd. ################ spawn csh ;# this is a comment expect "$prompt" ;# assume prompt is set already send "sleep 10\r" ;# run sleep command for 10 secs exec sleep 1 ;# give time to let sleep begin send "\cZ" ;# suspend it exec sleep 10 ;# wait for 10 seconds send "fg\r" ;# let sleep resume set timeout 5 ;# timeout expect after 5 secs expect "*$prompt" {print "control-Z stopped sleep's clock\n"} timeout {print "control-Z didn't stop sleep's clock\n"} # Listing 4: Test whether sleep counts time while suspended. ################ spawn csh expect $prompt for {set i 0} {1} {incr i} { send "a" expect { "\cG" break timeout break "a" } } print "driver accepted $i chars\n" # Listing 5: Determine longest input line acceptable to terminal # driver while in canonical mode. ################ spawn ... initialize for {} {1} {} { punish ;# punishing procedure defined elsewhere interact X ;# pass control to user } # Listing 6: Run application through a set of punishing interactions, # then let user interact. Repeat indefinitely. ################ spawn csh; set csh1 spawn_id spawn csh; set csh2 spawn_id send -i $csh1 "send tty\r" expect -i $csh1 -re "(/.*)\r" send -i $csh2 "send write $env(USER) $expect(1,string)\r" expect -i $csh1 -re "Message from .*" # Listing 7: Beginning of a script to start two processes that # interact with each other -- in this case, via write. ################ set csh [spawn csh] set cshnew [spawn csh.new] while {-1!=[gets stdin input]} { send -i $csh $input send -i $cshnew $input expect -i $csh -re ".+\r\n" set output $expect_out(buffer) expect -i $csh $output if ![string match output $expect_out(buffer)] { send_user "detected discrepancy on input $input\n" send_user "original csh output $output\n" send_user "new csh output $expect_out(buffer)\n" interact } } # Listing 8: Run two shells simultaneously from the same input, # stopping when there is a difference in their output. ################ ##### # # modem # ##### # «modem» (to ".modem") (defun eex-bounded () (interactive) (ee-strbounded 'eex "\n%*\n" "\n%*\n")) (global-set-key [f3] 'eex-bounded) # (find-fline "~/EXPECT/") # (find-fline "~/EXPECT/dialer") # (find-fline "~/EXPECT/dialer" "-open") # (find-node "(sh-utils)stty invocation") %* proc Exec {args} { puts $args puts -nonewline [eval exec $args] } set port /dev/ttyS2 Exec stty 115200 raw -echo < $port > $port Exec rm -fv /var/lock/LCK..ttyS2 /var/lock/LCK.004.066 spawn -noecho -open [open $port {RDWR NONBLOCK}] interact { "~~" return -o "Strike a key when ready . . .\r\n" {send "\n"} } %* %* proc Exec {args} { puts $args puts -nonewline [eval exec $args] } set port /dev/ttyS2 Exec stty 115200 raw -echo < $port > $port Exec rm -fv /var/lock/LCK..ttyS2 /var/lock/LCK.004.066 spawn -noecho -open [open $port {RDWR NONBLOCK}] puts yeah send {at$} expect "OK" %* expect_before "Strike a key when ready . . .\r\n" {send "\n"; exp_continue} send "at$" puts yeah expect "OK" {puts -nonewline OK} puts yeah %* (defun eexm-bounded () (interactive) (ee-strbounded 'write-ee "\n%*\n" "\n%*\n" "#!/usr/bin/expect proc Exec {args} { puts $args; puts -nonewline [eval exec $args] } set port /dev/modem exec stty 115200 raw -echo < $port > $port spawn -noecho -open [open $port {RDWR NONBLOCK}] set strike \"Strike a key when ready . . .\\r\\n\" \n" "\n" "$EET" "0777")) (global-set-key [f3] 'eexm-bounded) %* interact { "~~" return -o $strike {send "\n"} } %* %* proc expok {} { global strike expect { $strike { send "\n"; exp_continue } OK {} } } send "at$\r" expok %* %* set timeout 1 proc expok {} { global strike expect { $strike { send "\n"; exp_continue } OK { send {} } } } foreach command $argv { send "$command\r" expok } sleep 0.05 %* eet 'at$' 'at&$' 'atd$' 'ats$' # (find-fline "~/EXPECT/modem") %* set strike "Strike a key when ready . . .\r\n" proc expok {} { global strike interact { -o $strike { send "\r" } OK { send_user OK; return } } } send "at$\r" expok %* strace -q -f -o ~/s $EET close on exec "/etc/nsswitch.conf" ##### # # Simplifying the curses codes # ##### # «curses» (to ".curses") # (find-fline "/usr/doc/ncurses-base/") # (find-fline "/usr/doc/ncurses-bin/") # (find-fline "/usr/doc/ncurses-term/") # (find-vldifile "ncurses-base.list") # (find-vldifile "ncurses-bin.list") # (find-vldifile "ncurses-term.list") # See: Exploring Expect, p. 450; # (eeman "5 terminfo") # (eeman "5 termcap") # (eeman "captoinfo") # (eeman "console_codes") # (find-fline "/etc/terminfo/l/linux") pdsc /big/slinks2/dists/slink/main/source/libs/ncurses_4.2-3.dsc # (code-c-d "ncurses" "/usr/src/ncurses-4.2/") # (find-ncursesfile "misc/terminfo.src") # (find-ncursesfile "misc/terminfo.src" "linux|linux console") # (find-ncursesfile "misc/terminfo.src" "klone+sgr") # (find-ncursesfile "misc/terminfo.src" "ecma+color") # Esse bloquinho não funciona, mas o que vem depois funciona. set env(TERM) "ezork" set env(TERMCAP) {ezork: clr:^L: do:^J: cr:^M: csr:\E[%i%p1%d;%p2%dr: cm:\E[%d;%dH: } exec captoinfo exit # Esse aqui tá ok, mas ele não faz o que eu queria. set file [open /tmp/ezork.src w] puts $file {ezork|Test for groking Zork output, ind=\n, cr=\r, clear=\f, cup=\E[%p1%d;%p2%dH, csr=, } # cup=\E[%p1%d;%p2%dH, # csr=\E[%p1%d;%p2%dr, close $file set env(TERMINFO) /tmp exec tic /tmp/ezork.src set env(TERM) ezork # Esse bloco é o que funciona mais, mas o scroll dele é meio bobo. if {0} { # (find-ncursesfile "misc/terminfo.src" "linux|linux console") # (find-ncursesfile "misc/terminfo.src" "klone+sgr") # (find-ncursesfile "misc/terminfo.src" "ecma+color") set file [open /tmp/ezork.src w] puts $file {ezork|Test for groking Zork output, ind=^J, cr=^M, nel=^M^J, cols#80, lines#50, ndscr, cup=\E[%i%p1%d;%p2%dH, csr=\E[%i%p1%d;%p2%dr, clear=\E[H\E[J, dl=\E[%p1%dM, } # cup=\E[%p1%d;%p2%dH, # csr=\E[%p1%d;%p2%dr, close $file set env(TERMINFO) /tmp exec tic /tmp/ezork.src set env(TERM) ezork } ##### # # expect bugs in potato # 2000apr15 # ##### # «expect_bugs_potato» (to ".expect_bugs_potato") #* expect -c ' # stty raw stty -icanon while 1 { set usecs [lindex [time {expect -re .}] 0] set msecs [expr $usecs/1000.0] send_user "$msecs " } ' #* # 2001jan20: hm, it turns out that there is no bug here; I just # learned enough about ttys to why a "stty -icanon"/"stty raw" is # needed. But stty raw is often too aggressive. # (find-fline "/var/lib/dpkg/status" "Package: expect5.24\n") # (find-fline "/var/lib/dpkg/status" "Package: expect5.31\n") # (find-vldifile "" "expect") # (find-vldifile "expect5.24.postinst") # (find-vldifile "expect5.24.prerm") # (find-vldifile "expect5.31.list") # (find-vldifile "expect5.31.md5sums") # (find-vldifile "expect5.31.postinst") # (find-vldifile "expect5.31.prerm") # (find-vldifile "expect5.31.shlibs") # (find-fline "/usr/doc/expect5.31/FAQ.gz") # (find-fline "/usr/doc/expect5.31/FAQ.gz" "fake daemon") # (find-fline "/usr/doc/expect5.31/NEWS.gz" "new-regexp-features") psne http://www.scriptics.com/support/howto/regexp81.html http://dev.scriptics.com/doc/howto/regexp81.html # (find-fline "/var/lib/dpkg/status" "Package: exim") # (find-fline "$SDEBIAN/ls-lR.i") Pgrepp m/icq/ ##### # # making a texinfo file from the manpage # 2001apr15 # ##### # «expect.texi» (to ".expect.texi") # (find-fline "~/EXPECT/expect.man.txt") #* cd ~/EXPECT/ zcat /usr/share/man/man1/expect.1.gz \ | man2t2 \ | col -bx \ > expect.man.txt #* ##### # # bug-hunting on inetd services: logging stdin, stdout and stderr # 2000apr15 # ##### # «inetd_logger0» (to ".inetd_logger0") # Below are some frustrated attempts to write loggers for inetd # programs in expect. # see the expect book, p.245 and 251--. # expect: # (eeman "expect" 491) # interact: # (eeman "expect" 491) # user_spawn_id # error_spawn_id # tty_spawn_id expect -c ' expect { -i $user_spawn_id -re . { send $expect_out(buffer) exp_continue } -i $error_spawn_id -re . { send $expect_out(buffer) exp_continue } } ' expect -c ' spawn tclsh expect -i $user_spawn_id -re . { send $expect_out(buffer) send_user $expect_out(buffer) exp_continue } ' zcat /usr/share/man/man1/expect.1.gz # (find-expmanfile "") # (find-expmanfile "interact") expect -c ' spawn tclsh interact { -re (.) { send $interact_out(0,string) } -i $user_spawn_id -re (.) { send_user $interact_out(0,string) } -i $error_spawn_id -re (.) { send_error $interact_out(0,string) } } send_user "done.\n" ' expect -c ' spawn tclsh interact { -re (.) { send $interact_out(0,string) send_user $interact_out(0,string) } } send_user "done.\n" ' ##### # # expect5.31-dev # ##### # (find-available "expect5.31-dev") # (find-status "expect5.31-dev") # (find-vldifile "expect5.31-dev.list") # (find-fline "/usr/doc/expect5.31-dev/") # (find-fline "/usr/include/tcl8.3/expect.h") # (find-fline "/usr/include/tcl8.3/expect_tcl.h") # (find-fline "/usr/include/tcl8.3/expect_comm.h") # (find-fline "/usr/include/tcl8.3/tcldbg.h") # (eeman "3 libexpect5.31") A mental model for expect (tentative): Let's suppose that no new processes will be spawned and no processes will close in the time frame we're interested in; then Expect is communicating with n processes, P1..Pn, plus a special process, P0, which is the user. We'll ignore the distinction between each stdout/stderr pair, and between the three "std"s and the tty for P0; so Expect can send characters to any one of P0..Pn through a single channel, that we will call E->Pk. Also, Expect receives chars via channels that we will call Pk->E. We'll suppose that every time that Expect sends characters to any of the Pks the kernel call is ran immediately; so there is no need for output buffers. As for receiving characters, Expect waits for them using a "select" call, and when it is notified that there are characters waiting it reads these characters immediately and do all the state transitions it needs; only after getting back to a stable state it will do another "select" call. Expect never asks which of the Pk->E channels have characters; it just enters its "call select" mode from time to time. So we can suppose that input comes from one channel at a time; the "select" call receives either characters from exactly one of the channels, or a notification that a certain number of seconds have passed (1, say) and the processes have sent nothing. Each of the Pk->E channels has a buffer with its unprocessed characters. Every time we receive new characters we run a certain pattern matching routine on all these buffers of unprocessed characters. The pattern matchers are not optimized to suspend while we wait for new input to avoid reparsing things; every time we receive new characters -- and then we append them to some of the input buffers -- the buffers are reparsed anew. The order in which the characters have piled on the several input buffers is immaterial. The top of each of the buffers is a "temporary EOF", or "TEOF". Trying to matching a patterns and discovering that it would have to extend past the TEOF is not exactly a failure; the match is just incomplete. This distinction in important sometimes because it is a common operation to discover which characters do not match a pattern and flush them out. As far as I know there are no commands to replace the characters in a buffer by another arbitrary sequence of characters. The action at any given state is determined by trying to match the contents of the buffers agains certain patterns, and discovering "which pattern matches first". As the patterns are given by regexps I believe that we must use a sort of a stack machine (the stacks are for backtracking) with a separate stacks for each input buffer, and with some weird rules of backtracking (i.e., with some unusual rules to compose the individual pattern-matching automata) to let us test one buffer for a pattern, then another for another pattern, then, say, another pattern on the first buffer, and so on. To make it simpler to test which pattern matches first we will suppose that each "select" call returns exactlt one char, or a timeout; no blocks of characters. It should possible to devise optimization strategies to allow receiving blocks of characters at once (without changing the result) but it would be crazy to discuss that now. Is the "pi-calculus" the calculus designed to allow reasoning with confluent reductions on programs that interact via many channels, like Expect? ##### # # exec and spawn do NOT concatenate their arguments # 2004sep06 # ##### # (find-man "3tcl exec") # (find-expcommand "spawn") #* printf "{%s} {%s}\n" foo bar printf "{%s} {%s}\n" "foo bar" expect -c ' puts [exec printf "{%s} {%s}" foo bar ] puts [exec printf "{%s} {%s}" "foo bar"] spawn printf "{%s} {%s}\n" foo bar ; interact spawn printf "{%s} {%s}\n" "foo bar"; interact ' #* ##### # # getting extra input from a fifo # 2004sep06 # ##### # «input-from-fifo» (to ".input-from-fifo") # (find-angg "EXPECT/readfifo") # (find-man "1 mkfifo") # (find-node "(coreutils)mkfifo invocation") #* rm -Rv /tmp/myfifos/ mkdir /tmp/myfifos/ cd /tmp/myfifos/ mkfifo fifo1 (sleep 2; echo "echo foo" > fifo1; sleep 2; echo "echo bar" > fifo1) & cat < fifo1 cat < fifo1 #* # (find-expcommand "interact") rm -Rv /tmp/myfifos/ mkdir /tmp/myfifos/ cd /tmp/myfifos/ mkfifo fifo1 (sleep 2; echo "echo foo" > fifo1; sleep 2; echo "echo bar" > fifo1) & expect -c ' # spawn cat fifo1 # spawn sh -c "while true; do cat fifo1; done" spawn sh -c {while [ -r fifo1 ]; do cat fifo1; done} set readfifo_spawn_id $spawn_id spawn bash interact { -input $user_spawn_id -output $spawn_id eof {send_user "keyboard closed\n"; return} -input $readfifo_spawn_id -output $spawn_id eof {send_user "readfifo closed\n"; exp_continue} -input $spawn_id -output $user_spawn_id eof {send_user "sh closed\n"; return} } ' #* ##### # # answering ssh/rsh password requests # 2004sep30 # ##### # «passwords» (to ".passwords") # (find-angg ".zshrc" "autopasswd") # (find-angg "EXPECT/Sucuri") # (find-angg "EXPECT/Twu") # (find-expcommand "log_user") #* # I got the -echo/echo hint from Exploring Expect, p.199. # (find-expcommand "stty" "stty -echo") # (find-man "1 stty") # (find-node "(coreutils)stty invocation") # (find-node "(libc)Low-Level Terminal Interface") cat > /tmp/passwdprompt <<'%%%' #!/bin/sh echo Hello. # echo -n "edrx@sucuri.mat.puc-rio.br's password: " echo -n "edrx@angg.twu.net's password: " stty -echo read PASSWD stty echo echo echo you typed: $PASSWD %%% chmod 755 /tmp/passwdprompt #* /tmp/passwdprompt #* # (find-expcommand "interact") # (find-expcommand "interact" "-o flag") # (find-expcommand "interact" "-nobuffer flag") expect =(<<'%%%' spawn /tmp/passwdprompt set SUCURI sucuri.mat.puc-rio.br set TWU angg.twu.net interact { -o -nobuffer "edrx@${SUCURI}'s password: " { sleep 0.5; send "1234\n" } -nobuffer "edrx@${TWU}'s password: " { sleep 0.5; send "2345\n" } } %%%) #* ##### # # autopasswd (my script conflict with expect's) # 2019mar14 # ##### # «autopasswd» (to ".autopasswd") # (find-angg ".zshrc" "autopasswd") # (find-angg "EXPECT/autopasswd") # (find-zsh "apt-file search autopasswd") # (find-status "expect") # (find-vldifile "expect.list") # (find-udfile "expect/") # (find-vldifile "expect.list" "/usr/bin/expect_autopasswd") # (find-vldifile "expect.list" "/usr/bin/autopasswd") ##### # # receiving characters as they are typed # 2004oct08 # ##### # «noncanonical-mode» (to ".noncanonical-mode") # (find-node "(libc)Canonical or Not") # (find-node "(libc)Noncanonical Input") # (find-node "(libc)Local Modes") # (find-node "(coreutils)Input") # (find-node "(coreutils)Local") # (find-htetfile "BackspaceDelete.gz" "one-liner") #* eegcc <<<' void main() { int c; while(c = getchar()) printf("%d 0x%02X\n", c, c); } ' stty -icanon min 1 eec stty sane #* ##### # # logging the input and output of an interactive program # 2004dec18 # ##### # (find-man "1 script") #* expect -c ' spawn -open [set infile [open /tmp/i w]]; set infile_spawn_id $spawn_id spawn -open [set outfile [open /tmp/o w]]; set outfile_spawn_id $spawn_id spawn bash; set prog_spawn_id $spawn_id interact { -input $user_spawn_id -output "$prog_spawn_id $infile_spawn_id" -input $prog_spawn_id -output "$user_spawn_id $outfile_spawn_id" } close $outfile exit 0 ' # (find-fline "/tmp/o") # (find-sh "cat /tmp/i; echo; echo '===='; cat /tmp/o") #* # (find-pspage "$S/http/expect.nist.gov/doc/kibitz.ps") # On page 3 of http://expect.nist.gov/doc/kibitz.ps Don Libes uses # another idiom for connecting two processes: # while 1 { # expect { # -i $process1 -re .+ { send -i $process2 $expect_out(buffer) } # -i $process2 -re .+ { send -i $process1 $expect_out(buffer) } # } # } # but that was written before he had "interact". #* cat > /tmp/foo.tcl <<'%%%' proc li {str} { sleep 1; send_user -- "$str\n" } li {print(1+2)} li {-- comment} li {os.exit()} sleep 1 %%% expect /tmp/foo.tcl #* # This doesn't work. Why? expect -c ' spawn expect /tmp/foo.tcl; set id1 $spawn_id spawn lua50; set id2 $spawn_id interact { -input $id1 -output $id2 -output $user_spawn_id -input $id2 -output $id1 -output $user_spawn_id } ' #* # Logging input (this script works) expect -c ' spawn -open [set outfile [open /tmp/i w]]; set outfile_id $spawn_id spawn bash interact -output "$spawn_id $outfile_id" close $outfile exit 0 ' # (find-fline "/tmp/i") #* expect =(<<'%%%' puts $argv %%%) foo "bar plic ploc" moo # (find-udfile "expect/examples/kibitz") ##### # # A thread on emacs-devel about getconf, LINE_MAX, and PIPE_BUF # 2021sep08 # ##### # «getconf-pipe-buf» (to ".getconf-pipe-buf") # https://lists.gnu.org/archive/html/emacs-devel/2021-09/threads.html#00193 # https://lists.gnu.org/archive/html/emacs-devel/2021-09/msg00453.html getconf LINE_MAX # https://lists.gnu.org/archive/html/emacs-devel/2021-09/msg00478.html getconf PIPE_BUF # https://lists.gnu.org/archive/html/emacs-devel/2021-09/msg00483.html neither has PIPE_BUF # https://lists.gnu.org/archive/html/emacs-devel/2021-09/msg00681.html Barton patch # (find-man "1 getconf") # (find-sh "getconf -a") # (find-sh "getconf -a | sort") # (find-available "empty-expect") # http://empty.sourceforge.net/ # https://packages.debian.org/stretch/empty-expect https://stackoverflow.com/questions/32910661/pretend-to-be-a-tty-in-bash-for-any-command/32981392#32981392 https://stackoverflow.com/questions/1401002/how-to-trick-an-application-into-thinking-its-stdout-is-a-terminal-not-a-pipe https://blog.robertelder.org/don-libes-expect-unix-automation-tool/ https://news.ycombinator.com/item?id=31146862 The TTY Demystified (2008) (linusakesson.net) - Links to previous discussions https://news.ycombinator.com/item?id=41405364 Expect – Linux tool for automating interactive programs (die.net) # Local Variables: # coding: utf-8-unix # End: