Search code examples
pythonwindowsbatch-filecmdstring-formatting

String formatting not working inside for-if-do command for batch processing


I am trying to execute a windows batch command inside my python script using os.system(). My command looks like

os.system('''for %i in ("D:\\u\\demo4\\v2\\repository\\..\\p3\\*.aar") do if exist "D:\\u\\demo4\\v2\\repository\\com\\aws\sdk\\%~ni\\%~nxi" copy "%~i" "D:\\u\\demo4\\v2\\repository\\com\\aws\sdk\\%~ni\\%~ni.aar" /Y ''')
# it works fine...when path "D:\\u\\demo4\\v2\\repository" is hard coded

.This works perfectly. However now my requirement is that instead of hardcoding the directory path, i want to pass it as a variable "REPO_PATH" and use the string format capability of python to pass this path in my command . Therefore my command should be

os.system('''for %i in ("{}\\..\\p3\\*.aar".format(REPO_PATH)) do if exist "{}\\com\\aws\\sdk\\%~ni\\%~nxi".format(REPO_PATH) 
 copy "%~i" "{}\\com\\aws\sdk\\%~ni\\%~ni.aar".format(REPO_PATH) /Y ''')`

To my surprise this command does not work. I have included my python script file too. What am I missing here?? Any help. My Python script file is shown below along with the outputs I get as comments next to the commands.

import os,sys
REPO_PATH="D:\\u\\demo4\\v2\\repository"
print(REPO_PATH)


os.system('''for %i in ("D:\\u\\demo4\\v2\\repository\\..\\p3\\*.aar") do if exist "D:\\u\\demo4\\v2\\repository\\com\\aws\sdk\\%~ni\\%~nxi" copy "%~i" "D:\\u\\demo4\\v2\\repository\\com\\aws\sdk\\%~ni\\%~ni.aar" /Y ''')
# it works fine...when path "D:\\u\\demo4\\v2\\repository" is hard coded


os.system('''for %i in ("{}\\..\\p3\\*.aar".format(REPO_PATH)) do if exist "{}\\com\\aws\sdk\\%~ni\\%~nxi".format(REPO_PATH) copy "%~i" "{}\\com\\aws\sdk\\%~ni\\%~ni.aar".format(REPO_PATH) /Y ''')
#it gives error saying  ""{}\..\p3\*.aar".format was unexpected at this time."


Solution

  • This isn't a safe way to pass filenames to a shell at all. Ignoring that, though, the immediate problem is that you're putting .format(REPO_PATH) inside the shell code, whereas it needs to be executed by the Python interpreter, not by cmd.exe.

    Compare:

    # your original code, with print() instead of os.system(), to show the bug
    REPO_PATH="D:\\u\\demo4\\v2\\repository"
    print('''for %i in ("{}\\..\\p3\\*.aar".format(REPO_PATH)) do if exist "{}\\com\\aws\sdk\\%~ni\\%~nxi".format(REPO_PATH) copy "%~i" "{}\\com\\aws\sdk\\%~ni\\%~ni.aar".format(REPO_PATH) /Y ''')
    

    to

    # only one format(), on the entire string, to *fix* the bug
    REPO_PATH="D:\\u\\demo4\\v2\\repository"
    print('''for %i in ("{0}\\..\\p3\\*.aar") do if exist "{0}\\com\\aws\sdk\\%~ni\\%~nxi" copy "%~i" "{0}\\com\\aws\sdk\\%~ni\\%~ni.aar" /Y '''.format(REPO_PATH))
    

    ...you'll see that the former has .format(REPO_PATH) inside the script text being passed to the shell, whereas the latter actually replaces the instances before invoking the shell.