0

So I have this pretty simple line of code that opens up a .exe file that gets put inside the subprocess.call bracket. However, I always need to specify in full length the location of the .exe file that I'm trying to run. How do I make it so that I don't have to specify it by putting the .py file with the code below inside the same directory with the .exe file that I'm running?

import subprocess

def openHC():
    try:
        subprocess.call("R:/Codes/crackingAtHome/crackingAtHomeClient/hashcat.exe")
    except:
        print("something wrong happened")


openHC()

I tried to put the .py file in the same directory with no success. I still have to fully specify it for it to run.

  • If the `hashcat.exe` binary is in a folder specified in $PATH then you don't need the full path. Other workarounds might include putting the binary and .py file in the same folder, or `chdir()` before you call the subprocess(?). – Adam Smooch Dec 17 '22 at 20:29
  • That script is supposed to be run on different machines in which the crackingAtHomeClient folder might not be in the same directory. What's the best approach here? – Ryannnnnnnn Dec 17 '22 at 20:35
  • 1
    It shouldn't be your problem to know where `hashcat.exe` is. That's why path lookup exists: you execute `hashcat.exe`, and it's the job of whoever runs your script to ensure that `hashcat.exe` can be found in a directory on the search path. At most, I would provide a way for the user to specify an exact path via a command-line option or an environment variable. – chepner Dec 17 '22 at 21:00
  • You can actually just get CWD then add relative path to it, as long as relative path to executable is same for all machines. – jupiterbjy Dec 17 '22 at 21:15
  • I am confused. Do you want to put the .py and .exe files in the same directory? If so, the duplicate answer certainly isn't right. – tdelaney Dec 17 '22 at 21:17
  • yes, I want to put them together in the same place for the sake of conveniency. And also because I thought subprocess.call can just look up the programs that's in the same directory as the .py file it's in. Am I wrong to do that? Is there a better way? I just want to share the crackingAtHomeClient folder and be able to run the .py script without any further inputs. – Ryannnnnnnn Dec 17 '22 at 21:22

2 Answers2

1

When python runs a script, it usually includes the __file__ variable, naming the .py file being run. You can use that name to find other files in the same directory. This is usually an absolute path, but I don't think its required to be so, so its a good idea to make it absolute anyway. The pathlib provides a convenient way to do the calculations.

import subprocess
from pathlib import Path

try:
    parent_path = Path(__file__).absolute().parent
except:
    # parent path unknown, hope cwd works
    parent_path = Path(".")
    
def openHC():
    try:
        subprocess.call(f'{parent_path/"hashcat.exe"} --help', 
            shell=True)
    except:
        print("something wrong happened")

openHC()
tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

There are a few concepts to unpack:

Working directory

When a Python script is run, it usually starts with cwd (current working directory) as the pwd (present working directory) of the invoking shell.

So assuming we have a script /tmp/sub/print_cwd.py:

#!/usr/bin/env python3

from os import getcwd

print(getcwd())

Then we get the following outputs (with the part before the $ being the shell's current directory):

/tmp/sub$ python3 print_cwd.py
/tmp/sub
/tmp$ python3 sub/print_cwd.py
/tmp
<other location>$ python3 /tmp/sub/print_cwd.py
<other location>

File paths

They can be relative (from cwd) or absolute (from root a.k.a. / or C:\)

  • Relative paths can:
    • go deeper e.g. to sub/print_cwd.py from /tmp,
    • higher, using ../, or
    • any combination of the two e.g. to ../../tmp/sub/print_cwd.py from /home/user (up 2 levels to /, then back down, into tmp)

PATH

To address the problem of I don't know where everyone keeps their binaries/exe's, there is something called PATH (echo $PATH to see what yours is).

The tl;dr is that if a binary is in a folder on PATH, you can call it with only the binary name, e.g. hashcat.exe

Putting it together

So what your script (or any shell, for that matter) does, when you specif a filename (binary for execution, but also for file-reads) is check:

  • is there a file with this name in my pwd?
  • is there a file with this name [in a folder] on PATH?
  • Error: file not found

When you specify an absolute path, it knows exactly where to go, so it only looks there.

...What to do in your case?

Options:

  1. leave it to the user to ensure hashcat.exe is in a folder that is on their PATH, or
  2. Accept a location for hashcat.exe as a cli-argument to your script, then
    1. call hashcat.exe with an absolute path, or
    2. change your pwd to hashcat.exe's location with os.chdir()

NOTE: Option #1 was @chepner's suggestion, in an OP-comment.

Adam Smooch
  • 1,167
  • 1
  • 12
  • 27