0

I'm trying to write a part of a Python script what changes the root MySQL password under Linux for a small web-admin interface. I've followed the official MySQL documentation on changing the root password, and came up with this shell script, what works nicely:

shopt -s xpg_echo
# stopping running MySQL server
invoke-rc.d mysql stop

# creating init file in a mysqld readable location
cat > /var/lib/mysql/mysql-init <<END
UPDATE mysql.user SET Password=PASSWORD('x123') WHERE User='root';
FLUSH PRIVILEGES;
END

# running mysqld_safe with init-file in the background
mysqld_safe --init-file=/var/lib/mysql/mysql-init &

sleep 5

# stopping mysql
invoke-rc.d mysql stop

# deleting the init file
rm /var/lib/mysql/mysql-init

# starting mysql
invoke-rc.d mysql start

There is one part, where I have to start mysqld_safe and let it run for a few seconds and the stop it nicely with invoke-rc.d. In the shell script I could solve it with & and sleep 5.

My problem is that I don't know how could I do this in the Python script without using shell=True. I could do all the other parts with Popen and shlex.split(cmd), but & doesn't seem to go through either shlex.split(cmd) or through shell=False.

Is it just a simple problem with & in the command line or I really need shell=True for this? If not, do I need to use threads?

hyperknot
  • 13,454
  • 24
  • 98
  • 153
  • The `&` is interpreted by the shell, so you must use a shell with that syntax. You could duplicate that functionality in Python, however, by using the system calls `fork`, `exec*`, and `setsid`. – Keith Sep 09 '12 at 18:47
  • OK, I get the shell part. But wouldn't it be possible to put Popen in a thread? – hyperknot Sep 09 '12 at 19:06
  • Yes you can use a thread also. It depends on what exactly you mean by "background". To spawn a fully detached subprocess you need to use those system calls (among others), but for a short-lived process a thread should be fine. – Keith Sep 09 '12 at 20:18
  • All I wanted to do was wait about 5 seconds, while the process initializes and then call `invoke-rc.d mysql stop` to stop it. Background was just an idea for it, what worked well in the bash script. – hyperknot Sep 09 '12 at 21:06
  • BTW, looking more closely, how do you know the mysql_safe process finished? How do you know it exited successfully? Why can't you just wait for it, since your script blocks while sleeping, anyway? – Keith Sep 09 '12 at 21:30
  • It goes on forever. I don't know when does it finish, I just guess it takes < 1 sec, so 5 should be enough. I don't know what would be the best way of checking for it. Maybe pid, but a pid doesn't mean a successful init. – hyperknot Sep 09 '12 at 21:45

2 Answers2

1

I'm probably missing something, but wouldn't something like this work?

import time
import subprocess

p = subprocess.Popen(['mysqld_safe', '--init-file=/var/lib/mysql/mysql-init'])
time.sleep(5)
subprocess.call(['invoke-rc.d', 'mysql', 'stop'])
Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
  • mysqld_safe keeps running in the foreground, so Python is stuck at this command. This is why I thought using threads, but shell is easier. – hyperknot Sep 09 '12 at 19:06
  • Interesting--I didn't think that could happen with Popen. With every command or script that I've tried, Popen() returns immediately, and the process that it started keeps running. – Warren Weckesser Sep 09 '12 at 19:21
  • @zsero: Popen returns immediately. If you mean that the python process continues running after it executed all its code; it might be [another issue](http://stackoverflow.com/q/13243807/4279). – jfs Jun 09 '13 at 08:28
-1

& is a shell thing, so, yes, if you want to use & to run a command in the background, you need the shell. However, you can also do this entirely in Python:

proc = subprocess.Popen(["mysqld_safe", "--init-file=/var/lib/mysql/mysql-init"])
time.sleep(5)
proc.kill()
kindall
  • 178,883
  • 35
  • 278
  • 309