MountainX
MountainX

Reputation: 6337

How to do this just as elegantly in Python?

I'm just learning Python. One thing I hope to use Python for is Linux shell scripting. I've been studying some examples and practicing by converting my bash scripts to Python.

I just spent a few hours converting one of my bash scripts to Python and I was very disappointed with my resulting code. It was much more verbose and syntactically cluttered. It was certainly not concise and tight like the bash script I started with.

Then I stumbled across this (unrelated) Ruby script. Wow. It seems to give direct access to the shell, unlike Python which has a layer or two between the language and the shell.

#! /usr/bin/ruby
MAX_TIME_SINCE_START = 1800
begin
  curr_time = Time.new.to_i
  kslideshow_processes_list = `pgrep kslideshow.kss`.split("\n")
  kslideshow_processes_list.each { |kslideshow_process|
      kslideshow_process.strip!
      ps_result = `ps -p #{kslideshow_process} -o lstart`
      process_start_date = `ps -p #{kslideshow_process} -o
lstart`.split("\n")[1].strip
      get_date_command = "date -d \"#{process_start_date}\" +\"%s\""
      kslideshow_start_time = `#{get_date_command}`.to_i
      time_since_started = curr_time - kslideshow_start_time
      if time_since_started MAX_TIME_SINCE_START
          system( "kill #{kslideshow_process}" )
      end
  }
  sleep MAX_TIME_SINCE_START
end while true

This is the kind of code I was hoping would result from my switch from bash script to Python. Is it possible in Python to write shell scripts so cleanly?

It would be very educational for me to see the above code converted to Python by someone who knows what they are doing.

I don't intend to start a Ruby vs. Python discussion. I simply want to see how cleanly the above task can be implemented in Python by someone who knows more Python than I do. Is that a fair question for this site? Thanks

Upvotes: 0

Views: 159

Answers (2)

Anthon
Anthon

Reputation: 76642

You can IMO do this at least as elegant as in Ruby by using the plumbum package. There are ways to optimize away system calls (e.g. using dateutils to convert from a date format, or using psutils), but that would no longer be a comparison of calling system utilities (I hope I got the logic from the Ruby example correct):

from time import time, sleep
from plumbum.cmd import pgrep, ps, date, kill

MAX_TIME_SINCE_START = 5 # 1800

while True:
   curr_time = time()
   for kslideshow_process in pgrep("gimp").split():
      print kslideshow_process
   process_start_date = ps("-p",  kslideshow_process, "-o", "lstart"
                           ).split("\n")[1].strip()
   kslideshow_start_time = int(date("-d", process_start_date, '+%s'))
   print kslideshow_start_time
   time_since_started = curr_time - kslideshow_start_time
   if time_since_started > MAX_TIME_SINCE_START:
      kill([kslideshow_process])
   sleep(MAX_TIME_SINCE_START)

You can import any commandline program using from plumbum.cmd import ... and it is automatically available as a function that takes the commandline arguments as parameters. You can also make chains of commands:

chain = ls["-a"] | grep["-v", "\\.py"] | wc["-l"]
result = chain()

so there is far less often need for intermediate variables to carry results from one subshell to another.

Upvotes: 2

Rusty Weber
Rusty Weber

Reputation: 1582

Barring the bad ideas and ways you could poke your own eye out.. an example of the more efficient way to open a another process in python is as follows...


process = subprocess.Popen([MyCommand, parameter1, "parameter 2"], shell=False, stdout=subprocess.PIPE,
                                              stderr=subprocess.PIPE, stdin=subprocess.PIPE)
stdout,stderr = process.communicate()
return_code = process.poll()

Doing things with popen is a little bit more overhead than some other languages, but it offers a lot of versatility that no other scripting language I know of offers like getting output from many many processes live.

Upvotes: 1

Related Questions