0

So, I have a legacy script ts, that I need to call in a loop using several string arguments:

#User supplied
ts = '/d1/user/script.py'
adir = '/d1/user/adir'
mfile = '/d1/user/script.nc'
outdir = '/d1/user/park/'

metens = glob.glob(adir + '/*.nc')  #reads all files

for count, value in enumerate(metens):
    runcom = [ts, mfile, metens[count], outdir + os.path.basename(metens[count])]   
    runcom = " ".join(runcom) #This creates a string of CL arguments
    subprocess.call(['python2.7', runcom], shell=True) 

Now, when I run it, it calls python2.7 and opens the Python shell instead of running it as python2.7 runcom.

How can I make it run as a script instead of opening the shell?

12
  • is ts code or a file path? Commented Feb 20, 2018 at 22:52
  • @JorgeLeitão I have added more info. ts is a file. Commented Feb 20, 2018 at 22:54
  • Remove the argument shell=True? If I run python -c "import subprocess; subprocess.call(['python2.7', 'test.py'])" it tells me that the file does not exist and exits 1. If I create that file and run again, it runs the script. Commented Feb 20, 2018 at 22:55
  • Possible duplicate of Calling an external command in Python Commented Feb 20, 2018 at 22:59
  • I removed the shell=True, And I am getting ` [Errno 2] No such file or directory`. Even though all the necessary files exists. If I just copy paste the python2.7 runcom to a command line directly, it works. So nothing is wrong with the program.. Commented Feb 20, 2018 at 23:15

2 Answers 2

1

How To Fix It

args = ['script.py', 'first argument', 'second argument']
subprocess.call(['python2.7'] + args)
  • Don't use shell=True
  • Pass each argument as a separate list item; don't concatenate them into a string.

Why It Fails (with shell=True)

Let's take a simple case:

args = [ 'script.py', 'first argument' 'second argument' ]
args_str = ' '.join(args)
subprocess.call(['python2.7', args_str], shell=True)

What does this actually do?

# the above is the same as running this at a shell
sh -c python2.7 'script.py first argument second argument'

And what does that actually do? It runs python2.7 with no arguments at all (as the argument list is interpreted as $0 to the sh -c instance, but the script passed in the first element of the list contains only the string python2.7 and doesn't look at its $0 at all).


Why It Fails (without shell=True)

Let's take a simple case:

args = [ 'script.py', 'first argument' 'second argument' ]
args_str = ' '.join(args)
subprocess.call(['python2.7', args_str])

What does this actually do?

# the above is the same as running this at a shell
python2.7 'script.py first argument second argument'

...and what does that do, even if you have a script.py in your current directory?

python2.7: can't open file 'script.py first argument second argument': [Errno 2] No such file or directory

Why did that happen? Because you made your arguments part of the script's filename, and no filename with those argument values as part of its name exists.

Sign up to request clarification or add additional context in comments.

Comments

0

The linked answer doesn't directly answer my question

for count, value in enumerate(metens):
    subprocess.call(['python2.7', ts, mfile, metens[count], outdir + os.path.basename(metens[count]]) 

The runcom, if constructed inside the subprocess, works. But if I construct it outside, I get a no file error.

5 Comments

Is this an attempt to answer the question?
Yes, this gives me the desired files. Though I am sure there is a better way of doing this. I am just leaving it in till something better comes along.
No -- there isn't something better. This is the way it should be done.
(well -- you can construct it outside; what you need to avoid is condensing it down to a string, as opposed to keeping it as a list).
Thank you. I didn't know know what this was working. But I got it now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.