2

I'm trying to write a bash function named myrun, such that doing

myrun script.py

with a Python file:

#MYRUN:nohup python -u script.py &
import time
print 'Hello world'
time.sleep(2)
print 'Once again'

will run the script with the command specified in the first line of the file, just after #MYRUN:.

What should I insert in .bashrc to allow this? Here is what I have now:

myrun () {
[[ "1ドル" = "" ]] && echo "usage: myrun python_script.py" && return 0
<something with awk here or something else?>
}
Ed Morton
209k18 gold badges90 silver badges212 bronze badges
asked Jan 16, 2016 at 16:15
19
  • That sounds like an awful lot of work just to avoid writing a second script... Commented Jan 16, 2016 at 16:18
  • 1
    Hang on - you want to write a bash function that calls an awk script when called from python? Doesn't that sound a teeny bit like you might be going off the rails? Commented Jan 16, 2016 at 16:31
  • @EdMorton: No, not called from Python. Called from bash with myrun script.py. Commented Jan 16, 2016 at 16:32
  • So it's a python script that calls awk when it's called from bash? That's not any better. Commented Jan 16, 2016 at 16:34
  • 1
    @Basj You can! As an example, if you don't see --no-fork on the command line, you could do: subprocess.Popen(['nohup', sys.executable, sys.argv[0], '--no-fork'] + sys.argv[1:]); exit(). (I'd advise you check that --no-fork works before following this example though, or you'll end up with a process that keeps spawning then dying). Commented Jan 16, 2016 at 18:01

2 Answers 2

1

A minimalist version:

$ function myrun {
 [[ "1ドル" = "" ]] && echo "usage: myrun python_script.py" && return
 local cmd=$(head -n 1 < "1ドル" | sed s'/# *MYRUN://')
 $cmd
}
$ myrun script.py
appending output to nohup.out
$ cat nohup.out
Hello world
Once again 
$

(It's not clear to me whether you're better off using eval "$cmd" or simply $cmd in the last line of the function, but if you want to include the "&" in the MYCMD directive, then $cmd is simpler.)

With some basic checking:

function myrun {
 [[ "1ドル" = "" ]] && echo "usage: myrun python_script.py" && return
 local cmd=$(head -n 1 <"1ドル")
 if [[ $cmd =~ ^#MYRUN: ]] ; then cmd=${cmd#'#MYRUN:'}
 else echo "myrun: #MYRUN: header not found" >&2 ; false; return ; fi
 if [[ -z $cmd ]] ; then echo "myrun: no command specified" >&2 ; false; return; fi
 $cmd # or eval "$cmd" if you prefer
}
answered Jan 16, 2016 at 16:32
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Maybe we should add something to make $cmd empty if #MYRUN: is not found... Currently it would try to run the first line anyway!
If your command is specified with shell syntax, it may be cleaner to use eval "$cmd" rather than just $cmd (which has totally different rules for how the command is parsed).
I'd argue that the eval approach will always be more desirable. See BashFAQ #50 -- mywiki.wooledge.org/BashFAQ/050 -- for a discussion of the pitfalls in the other approach (quotes are treated as literal data, spaces can't possibly be escaped, etc).
1

This is unrelated to Bash. Unfortunately, the shebang line cannot portably contain more than a single argument or option group.

If your goal is to specify options to Python, the simplest thing is probably a simple sh wrapper:

#!/bin/sh
nohup python -u <<'____HERE' &
.... Your Python script here ...
____HERE
answered Jan 16, 2016 at 16:24

1 Comment

I'd argue that even simpler than this would be to do nohup's work in native Python; it's not that hard to reopen the standard FD set and set signal-handling behavior for HUP.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.