0

I'm looking for a way to write a few batch scripts to use as custom shell commands using python.

Here's a simple example:

FILENAME: gotofile.bat (put this batch commands file somewhere visible from %PATH%)

@setlocal enableextensions & "C:/Python27/python.exe" -x "%~f0" %* & goto :EOF 

# Looks for a file on disk and take me there
import sys
import os
if len(sys.argv) == 2:
    for root, dirnames, filenames in os.walk(os.getcwd()):
        for filename in filenames:
            if filename == sys.argv[1]:
                print 'TAKING YOU TO: %s'%root
                os.system('cls')
                os.system('title %s'%root)
                os.system('cd %s'%root)
                quit()

Now from a cmd shell type gotofile some_file_you_wish_to_find.ext (pick a file that is not too far away, or else os.walk will take a while)

Assuming it exists, Python should find your file, print where it would like to take you, the cls os.system call will correctly clear your screen but the two other os.system calls don't do anything.

Is there any way of making this work? Or will I have to do this all natively in batch?

cfi
  • 10,915
  • 8
  • 57
  • 103
Fnord
  • 5,365
  • 4
  • 31
  • 48
  • 2
    `os.system` spawns a new subshell to run your command in. Whatever you do there (unless it's something global, like deleting a file or making a registry edit) is not going to affect the parent shell of your current script. – abarnert Oct 22 '13 at 19:01
  • Use `os.chdir()` to change your own current directory. See http://stackoverflow.com/questions/7387276/set-window-name-in-python to set your console title. – cdarke Oct 22 '13 at 19:22
  • @abarnert so why would os.system('cls') clear screen in the current shell python is being launched from? Like if you open a cmd shell and type this: C:\Python27\python.exe -c "import os;os.system('cls')" – Fnord Oct 22 '13 at 20:12
  • @Fnord: Clearing the screen is global, in the sense that it affects the terminal window, not the shell—whatever one program does in that terminal window affects anything else running in that terminal window. Setting environment variables or changing the working directory is different not global in that sense. (The fact that, on Windows, `cmd.exe` is both the shell program and the terminal program can make things confusing…) – abarnert Oct 22 '13 at 20:22
  • @cdarke i tried os.chdir() but the problem is that once python exists the shell's %cd% remains it it's original location. ultimabely what i'm trying to do is to affect the shell python is being run from, like changing it's title. Speaking of, thanks for the poiner, that worked. I'll look in that direction to see if it's possible to do more operations (like cd) – Fnord Oct 22 '13 at 20:25

2 Answers2

2

Yes, with the changes shown -- you could probably shorten the batch file portion by putting some of the &'s back in.

@echo off
rem = """
setlocal enableextensions
set PYTHON="C:/Python27/python.exe"
%PYTHON% -x "%~f0" %*
goto endofPython """

# Your python code goes here ..

if __name__ == "__main__":
    # Looks for a file on disk and take me there
    import sys
    import os
    if len(sys.argv) == 2:
        for root, dirnames, filenames in os.walk(os.getcwd()):
            for filename in filenames:
                if filename == sys.argv[1]:
                    print 'TAKING YOU TO: %s' % root
                    command = '&'.join(['cls',
                                        'title %s' % root,
                                        'cd %s' % root,
                                        'cmd /k'])
                    os.system(command)

rem = """
:endofPython """

Note: If Python is installed, you should be able to just use python -x "%~f0" %* instead of hard-coding the full path to python.exe.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • this can't be called from another batch and return. – cure Oct 22 '13 at 21:49
  • @martineau thanks for this example. It's achieves my example fine! Only hiccup i see with your solution is that it seems to blow away any previous history (you'd access with arrow up/down). But thanks for this! – Fnord Oct 22 '13 at 22:20
  • @nephi12: I think in that situation all you'd have to do is type `exit` at the command prompt to return to the caller batch. – martineau Oct 22 '13 at 22:23
  • that would not save the cd or the title – cure Oct 22 '13 at 22:46
  • @nephi12: True, because `os.system()` executes the commands in a subshell and those sort of environmental changes would be lost when it returns. However, it's not clear from the OP's question whether those limitations when calling it from another batch file are an issue or not. – martineau Oct 22 '13 at 23:25
1

No.

for /f "delims==" %%i in ('dir "%SystemDrive%" /s /b^|find "%~1" /i') do (echo TAKING YOU TO: %%i&timeout /nobreak 1 >nul&cls&title %%~dpi&cd /d "%%~dpi")

this should do what you want.

cure
  • 2,588
  • 1
  • 17
  • 25
  • 2
    Thanks for your submission. Recreating the example above in pure batch isn't the problem i'm trying to solve. What i want is to make .bat files that run python to do tasks. So far it looks like i can do everything i want short of change dir commands, and maybe set environment variables. – Fnord Oct 22 '13 at 20:47