<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>expect &amp;mdash; Little Step</title>
    <link>https://rex.writeas.com/tag:expect</link>
    <description></description>
    <pubDate>Sat, 09 May 2026 23:25:57 +0000</pubDate>
    <item>
      <title>Quick introduction about Expect</title>
      <link>https://rex.writeas.com/quick-introduction-about-expect?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[The first import thing is how to debug&#xA;Expect with pattern and actions&#xA;Spawn new process&#xA;Interact with spawn process and continue&#xA;Signal handling&#xA;&#xA;Expect is a very useful tool to automate work with interactive applications, while also it is a very old. It is based on Tcl language which was created at 1988, and is not seen much nowdays except in test domain.&#xA;&#xA;The expect script is written with Tcl, and the syntax is a little wired compared with other popular language nowdays.&#xA;&#xA;The only scenario I used expect many years ago was to automatic ssh login. And after I know how to use SSH key to login, I abandoned it.&#xA;&#xA;I came up to expect recently because of the same scenario, SSH login. I need to ssh jump several times to reach the target server, and due to the system restriction, the ssh key can&#39;t be saved permently and will lost after reboot.&#xA;&#xA;The scenario is a little complicated compared with my old case. In order to know how to better write the expect script, I read the Exploring Expect: A Tcl-based Toolkit for Automating Interactive Programs book. The book is nice-written and worth reading if you want to learn little about Tcl or expect.&#xA;&#xA;Here some tips I learn from the book.&#xA;&#xA;a id=&#34;orgc6947f8&#34;/a&#xA;&#xA;The first import thing is how to debug&#xA;&#xA;The simple ways is to use -d option. Here are several ways:&#xA;&#xA;1: add -d with expect command&#xA;$ expect -d sample.exp&#xA;&#xA;2: add -d at the first line of expect script&#xA;!/usr/bin/env expect -d&#xA;&#xA;3: add expinternal 1 in the script&#xA;spawn telnet abc.net&#xA;expinternal 1&#xA;&#xA;expect &#34;Login: &#34;&#xA;send &#34;don\r&#34;&#xA;expect &#34;Password: &#34;&#xA;send &#34;swordfish\r&#34;&#xA;&#xA;4: you can also use -D 1 option for expect to trigger gdb liked debugger&#xA;$ expect -D1 sample.exp&#xA;1: expect &#34;hi\n&#34;&#xA;&#xA;dbg1.0  # 5: use strace level to print statments before excuted&#xA;like the set -x in shell&#xA;expect -c &#34;strace 4&#34; sample.exp&#xA;&#xA;a id=&#34;orge0c1855&#34;/a&#xA;&#xA;Expect with pattern and actions&#xA;&#xA;You can use expect with may patterns and actions, just like switch in C:&#xA;&#xA;expect {&#xA;    &#34;hi&#34; { send &#34;You said hi\n&#34;}&#xA;    &#34;hello&#34; { send &#34;Hello yourself\n&#34;}&#xA;    &#34;bye&#34; { send &#34;That was unexpected\n&#34;}&#xA;&#xA;    # a special pattern default(without quotation) is for timeout and EOF&#xA;    default {send &#34;timeout or eof\n&#34;}&#xA;}&#xA;&#xA;Expect command support both globing and regex for pattern matching. The options are -gl- and -re, the default is globing(-gl).&#xA;&#xA;The matched string is saved in expectout(0,string), and any matching and previously unmatched output is saved in variable expectout(buffer).&#xA;&#xA;The command expcontinue allows expect itself to continue executing rather than returning as it normally would.&#xA;&#xA;a id=&#34;org559106b&#34;/a&#xA;&#xA;Spawn new process&#xA;&#xA;You can spawn command to create new process like this:&#xA;&#xA;spawn ftp abc.net&#xA;expect &#34;Name&#34;&#xA;send &#34;anonymous\r&#34;&#xA;expect &#34;Password:&#34;&#xA;send &#34;don@libes.com\r&#34;&#xA;&#xA;But if the command is dynamic, a variable for example, you need to use with eval command. Eval in expect is like eval in shell, it will expand the variable and execute the command.&#xA;&#xA;!/usr/local/bin/expect --&#xA;set timeout [lindex $argv 0]&#xA;&#xA;spawn the command from argv with eval&#xA;eval spawn [lrange $argv 1 end]&#xA;expect&#xA;&#xA;a id=&#34;org26fcc8a&#34;/a&#xA;&#xA;Interact with spawn process and continue&#xA;&#xA;The simple usage for the interact it to return the control to the user.&#xA;&#xA;Actually interact provides the functions like expect with patterns and actions.&#xA;&#xA;Simple example is:&#xA;&#xA;spawn ftp abc.net&#xA;...&#xA;&#xA;interact {&#xA;    &#34;~d&#34;        {puts [exec date]}&#xA;    &#34;~e&#34;        exit&#xA;    &#34;foo&#34;       {puts &#34;bar&#34;}&#xA;}&#xA;&#xA;When use input &#34;~d&#34;, date command will be executed, and the result is echoed, and so on.&#xA;&#xA;It also provides the function to break or continue execution like this:&#xA;&#xA;while {1} {&#xA;    interact &#34;+&#34; break &#34;-&#34; continue&#xA;}&#xA;&#xA;In the above loop, if a user presses &#34;+“, the interact returns and the loop breaks. If the &#34;-&#34; is pressed, the interact returns, and the while loop continues.&#xA;&#xA;a id=&#34;org84635ad&#34;/a&#xA;&#xA;Signal handling&#xA;&#xA;The trap is used to handle singal, simple example is like this:&#xA;&#xA;trap intproc SIGINT&#xA;trap {&#xA;    senduser &#34;bye bye&#34;&#xA;    exit&#xA;} SIGINT&#xA;&#xA;And a special singal SIGWCH is for window size change, the handler is like this:&#xA;&#xA;trap {&#xA;    set rows [stty rows]&#xA;    set cols [stty columns]&#xA;    stty rows $rows columns $cols &lt; $spawn_out(slave,name)&#xA;} WINCH&#xA;&#xA;\#tcl #expect #ssh]]&gt;</description>
      <content:encoded><![CDATA[<ul><li><a href="#orgc6947f8" rel="nofollow">The first import thing is how to debug</a></li>
<li><a href="#orge0c1855" rel="nofollow">Expect with pattern and actions</a></li>
<li><a href="#org559106b" rel="nofollow">Spawn new process</a></li>
<li><a href="#org26fcc8a" rel="nofollow">Interact with spawn process and continue</a></li>
<li><a href="#org84635ad" rel="nofollow">Signal handling</a></li></ul>

<p><a href="https://man7.org/linux/man-pages/man1/expect.1.html" rel="nofollow">Expect</a> is a very useful tool to automate work with interactive applications, while also it is a very old. It is based on <a href="https://en.wikipedia.org/wiki/Tcl" rel="nofollow">Tcl</a> language which was created at 1988, and is not seen much nowdays except in test domain.</p>

<p>The expect script is written with Tcl, and the syntax is a little wired compared with other popular language nowdays.</p>

<p>The only scenario I used expect many years ago was to automatic ssh login. And after I know how to use SSH key to login, I abandoned it.</p>

<p>I came up to expect recently because of the same scenario, SSH login. I need to ssh jump several times to reach the target server, and due to the system restriction, the ssh key can&#39;t be saved permently and will lost after reboot.</p>

<p>The scenario is a little complicated compared with my old case. In order to know how to better write the expect script, I read the <a href="https://www.amazon.com/Exploring-Expect-Tcl-based-Automating-Interactive-ebook-dp-B0043D2EI6/dp/B0043D2EI6/ref=mt_other?_encoding=UTF8&amp;me=&amp;qid=" rel="nofollow">Exploring Expect: A Tcl-based Toolkit for Automating Interactive Programs</a> book. The book is nice-written and worth reading if you want to learn little about Tcl or expect.</p>

<p>Here some tips I learn from the book.</p>

<p><a id="orgc6947f8" id="orgc6947f8"></a></p>

<h1 id="the-first-import-thing-is-how-to-debug" id="the-first-import-thing-is-how-to-debug">The first import thing is how to debug</h1>

<p>The simple ways is to use <code>-d</code> option. Here are several ways:</p>

<pre><code class="language-tcl"># 1: add -d with expect command
$ expect -d sample.exp

# 2: add -d at the first line of expect script
#!/usr/bin/env expect -d

# 3: add exp_internal 1 in the script
spawn telnet abc.net
exp_internal 1

expect &#34;Login: &#34;
send &#34;don\r&#34;
expect &#34;Password: &#34;
send &#34;swordfish\r&#34;

# 4: you can also use -D 1 option for expect to trigger gdb liked debugger
$ expect -D1 sample.exp
1: expect &#34;hi\n&#34;

dbg1.0&gt;

# 5: use strace &lt;level&gt; to print statments before excuted
# like the set -x in shell
expect -c &#34;strace 4&#34; sample.exp
</code></pre>

<p><a id="orge0c1855" id="orge0c1855"></a></p>

<h1 id="expect-with-pattern-and-actions" id="expect-with-pattern-and-actions">Expect with pattern and actions</h1>

<p>You can use expect with may patterns and actions, just like <code>switch</code> in C:</p>

<pre><code class="language-tcl">expect {
    &#34;hi&#34; { send &#34;You said hi\n&#34;}
    &#34;hello&#34; { send &#34;Hello yourself\n&#34;}
    &#34;bye&#34; { send &#34;That was unexpected\n&#34;}

    # a special pattern default(without quotation) is for timeout and EOF
    default {send &#34;timeout or eof\n&#34;}
}
</code></pre>

<p>Expect command support both globing and regex for pattern matching. The options are <code>-gl-</code> and <code>-re</code>, the default is globing(<code>-gl</code>).</p>

<p>The matched string is saved in <code>expect_out(0,string)</code>, and any matching and previously unmatched output is saved in variable <code>expect_out(buffer)</code>.</p>

<p>The command <code>exp_continue</code> allows expect itself to continue executing rather than returning as it normally would.</p>

<p><a id="org559106b" id="org559106b"></a></p>

<h1 id="spawn-new-process" id="spawn-new-process">Spawn new process</h1>

<p>You can spawn command to create new process like this:</p>

<pre><code class="language-tcl">spawn ftp abc.net
expect &#34;Name&#34;
send &#34;anonymous\r&#34;
expect &#34;Password:&#34;
send &#34;don@libes.com\r&#34;
</code></pre>

<p>But if the command is dynamic, a variable for example, you need to use with <code>eval</code> command. <code>Eval</code> in expect is like <code>eval</code> in shell, it will expand the variable and execute the command.</p>

<pre><code class="language-tcl">#!/usr/local/bin/expect --
set timeout [lindex $argv 0]

# spawn the command from argv with eval
eval spawn [lrange $argv 1 end]
expect
</code></pre>

<p><a id="org26fcc8a" id="org26fcc8a"></a></p>

<h1 id="interact-with-spawn-process-and-continue" id="interact-with-spawn-process-and-continue">Interact with spawn process and continue</h1>

<p>The simple usage for the <code>interact</code> it to return the control to the user.</p>

<p>Actually <code>interact</code> provides the functions like <code>expect</code> with patterns and actions.</p>

<p>Simple example is:</p>

<pre><code class="language-tcl">spawn ftp abc.net
# ...

interact {
    &#34;~d&#34;        {puts [exec date]}
    &#34;~e&#34;        exit
    &#34;foo&#34;       {puts &#34;bar&#34;}
}
</code></pre>

<p>When use input “~d”, date command will be executed, and the result is echoed, and so on.</p>

<p>It also provides the function to break or continue execution like this:</p>

<pre><code class="language-tcl">while {1} {
    interact &#34;+&#34; break &#34;-&#34; continue
}
</code></pre>

<p>In the above loop, if a user presses “+“, the interact returns and the loop breaks. If the “–” is pressed, the interact returns, and the while loop continues.</p>

<p><a id="org84635ad" id="org84635ad"></a></p>

<h1 id="signal-handling" id="signal-handling">Signal handling</h1>

<p>The trap is used to handle singal, simple example is like this:</p>

<pre><code class="language-tcl">trap intproc SIGINT
trap {
    send_user &#34;bye bye&#34;
    exit
} SIGINT
</code></pre>

<p>And a special singal <code>SIGWCH</code> is for window size change, the handler is like this:</p>

<pre><code class="language-tcl">trap {
    set rows [stty rows]
    set cols [stty columns]
    stty rows $rows columns $cols &lt; $spawn_out(slave,name)
} WINCH
</code></pre>

<p>#tcl <a href="https://rex.writeas.com/tag:expect" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">expect</span></a> <a href="https://rex.writeas.com/tag:ssh" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ssh</span></a></p>
]]></content:encoded>
      <guid>https://rex.writeas.com/quick-introduction-about-expect</guid>
      <pubDate>Sun, 17 Jan 2021 04:01:51 +0000</pubDate>
    </item>
  </channel>
</rss>