How to perform a root command with Pexpect?
<p>I'm working on a python program to assist with the apt-get tool. I want to use pexpect to download the chosen package. I believe I'm getting stuck at the child.expect line. It seems to timeout when it comes to that line.</p>

<pre><code>butt = "vlc"
child = pexpect.spawn('sudo apt-get install ' + butt)
child.logfile = sys.stdout
child.expect('[sudo] password for user1: ')
child.sendline('mypassword')
</code></pre>

<p>This is the log file.</p>

<pre class="lang-none prettyprint-override"><code>TIMEOUT: Timeout exceeded.
&lt;pexpect.spawn object at 0xb5ec558c&gt;
version: 3.2
command: /usr/bin/sudo
args: ['/usr/bin/sudo', 'apt-get', 'install', 'vlc']
searcher: &lt;pexpect.searcher_re object at 0xb565710c&gt;
buffer (last 100 chars): '[sudo] password for user1: '
before (last 100 chars): '[sudo] password for user1: '
after: &lt;class 'pexpect.TIMEOUT'&gt;
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 27641
child_fd: 4
closed: False
timeout: 30
delimiter: &lt;class 'pexpect.EOF'&gt;
logfile: &lt;open file '&lt;stdout&gt;', mode 'w' at 0xb74d8078&gt;
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
</code></pre>

<p>UPDATE:</p>

<p>The password gets sent just fine. It also expects the next line as well, but then enters "Y" and does nothing.</p>

<pre><code>child = pexpect.spawn('sudo apt-get install ' + butt)
child.logfile = sys.stdout
child.expect_exact('[sudo] password for user1: ')
child.sendline('mypass')
child.expect_exact('Do you want to continue? [Y/n] ')
child.sendline('Y')
</code></pre>

<p>SOLVED: </p>

<p>I needed to add this line at the end.</p>

<pre><code>child.expect(pexpect.EOF, timeout=None)
</code></pre>

<p>The immediate problem is that this:</p>

<pre><code>child.expect('[sudo] password for user1: ')
</code></pre>

<p>uses a regular expression. The <code>[...]</code> construct has special meaning in regular expressions, so what you're actually waiting for there is one of the letters "d", "o", "s", or "u" followed by the text <code>password for user1:</code>. But <code>sudo</code> is sending the text <code>[sudo]</code> first and the regular expression doesn't match that, because the final character of it is <code>]</code> not one of those letters.</p>

<p>There are numerous possible solutions to this. You can just have it match <code>password for user1:</code>. You can use <code>expect_exact()</code> as suggested by JLeClerc (which is the solution I also favor). You can escape the brackets in your regular expression so they don't have their usual meaning: <code>\[sudo\]</code> (note that when specifying this as a Python string, you will need to double the backslashes or use a raw string literal).</p>

<p>The other problem is that if you have already given your password in the last few minutes, you may not be prompted for it. Then the <code>expect()</code> call will definitely time out waiting for it. The easiest way to address this is to issue <code>sudo -k</code> first. You can even do it on the same command line:</p>

<pre><code>child = pexpect.spawn('sudo -k; sudo apt-get install ' + butt)
</code></pre>

python linux ubuntu pexpect