Powershell script equivalent of Unix "shell function" - python

This is basically a duplicate of Change the current directory from a Bash script, except that I'm on windows and want to be able to change my command line directory from a powershell script.
I'm actually running a python script from the powershell file, parsing the output directory from that python script, and then using that output as the dir to change to, so if there's a way to do this from within the python script instead of the powershell file extra points!
To be 100% clear, yes I know about "cd" and "os.chdir", and no that's not what I want - that only changes the current directory for the script or batch file, NOT the command line that you are running from!
Code follows (batch file was my first attempt, I want it to be PS1 script):
sw.bat - parent dir added to sys $PATH
#echo off
set _PY_CMD_="python C:\code\switch\switch.py %*"
for /f "tokens=*" %%f in ('%_PY_CMD_%') do (
cd /d %%f
)
switch.py
import os
import argparse
LOCAL = r'C:\code\local'
def parse_args():
parser = argparse.ArgumentParser(description='Workspace manager tool.')
parser.add_argument('command', type=str, help='The command to execute, or workspace to switch to.')
return parser.parse_args()
def execute_command(command):
if command in ['l', 'local']:
print(LOCAL)
def main():
args = parse_args()
execute_command(args.command)
if __name__ == '__main__':
main()

If I got your question right, a simplistic approach would involve using [SS64]: FOR /F.
script.py:
target_dir = r"C:\Program Files"
print(target_dir)
script.bat:
#echo off
set _PY_CMD="e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script.py
for /f "tokens=*" %%f in ('%_PY_CMD%') do (
pushd "%%f"
)
Output:
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q057062514]> ver
Microsoft Windows [Version 10.0.18362.239]
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q057062514]> script.bat
[cfati#CFATI-5510-0:C:\Program Files]>
[cfati#CFATI-5510-0:C:\Program Files]> popd
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q057062514]>
Notes:
I used pushd (instead of cd) because simple popd would return to the original directory. The drawback is that one has to remember (the stack) how many times they called pushd in order to match the correspondent popds. If want to switch to cd, use it like: cd /d %%f
#EDIT0:
At the beginning, the question was for batch only, after that the PowerShell (PS) requirement (which can qualify as a different question) was added. Anyway, here's a simple (dummy) script that does the trick (I am not a PS expert).
script.ps1:
$PyCmdOutput = & 'e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe' 'script.py'
Set-Location $PyCmdOutput
Output:
PS E:\Work\Dev\StackOverflow\q057062514> .\script.ps1
PS C:\Program Files>

Try os.chdir in Python:
os.chdir(path)
Change the current working directory to path. Availability: Unix, Windows.

Here's what I would do if you want to do the directory changes purely in batch:
Create a home directory Var of the Batch file you are calling your Python from.
SET homeDir=%cd%
Then use cd to go into the desired directory. Once the program is in the directory, create a new command prompt using start "Title here (optional)" cmd.exe
Finally, return to the home directory with
cd "%homeDir%"
The script might look something like this:
#echo off
REM using cd with no arguments returns the current directory path
SET homeDir=%cd%
REM set home Directory
cd "%desiredDirectory%"
REM moved directory
start "thisIsAName" cmd.exe
REM created new "shell" if you will
cd "%homeDir%"
REM returned to home directory
pause

With the help of CristiFati, I got this working in a batch file. That solution is posted in the question. After some more googling, I've translated the batch file solution to a Powershell Script solution, which is below:
$command = "& python C:\code\switch\switch.py $args"
Invoke-Expression $command | Tee-Object -Variable out | Out-Null
set-location $out
No changes required to the Python file.
Note - this answer is provided for those who want to take in any number of arguments to the python script and suppress stdout when calling the python script.

Related

$PATH has the correct entry, but python fails to execute

I have my PATH variable to point to my-project directory. However when I try to run the python script from outside it does not work. May be it tooks simple, but i am not able to find an answer.
I have googled and done it right. Please help me point out the mistake.
Also, I have added the path to my .bash_profile but not working:
root#c3-redsuren-vm01:~# cat .bash_profile
export PATH="$PATH:/opt/mssql-tools/bin:/root/my-project"
root#c3-redsuren-vm01:~/my-project# python print_test.py
hello world
root#c3-redsuren-vm01:~/my-project# ./print_test.py
hello world
Going back to home dir which is /root
root#c3-redsuren-vm01:~/my-project# cd ~
root#c3-redsuren-vm01:~# pwd
/root
Try to execute script from home dir:
root#c3-redsuren-vm01:~# python print_test.py
python: can't open file 'print_test.py': [Errno 2] No such file or directory
root#c3-redsuren-vm01:~# ./print_test.py
-bash: ./print_test.py: No such file or directory
root#c3-redsuren-vm01:~# python print_test.py
python: can't open file 'print_test.py': [Errno 2] No such file or
directory
Path details:
root#c3-redsuren-vm01:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/mssql-tools/bin:/root/my-project
root#c3-redsuren-vm01:~#
root#c3-redsuren-vm01:~/my-project# python print_test.py
hello world
If I go to the my-project directory and run the script it works fine.
Thanks in advance!
The argument to Python should be a file name; Python does not examine your PATH to look in directories other than the current directory.
The standard way on Linux-like systems to make a script executable from anywhere is to put in a valid shebang and mark the script itself as executable and save it in a directory which is in your PATH; then you can run it from anywhere with just the file name.
bash$ pwd
/root
bash$ echo "$PATH" | tr ':' '\n' | grep my_project
/root/my_project
bash$ cat >my_project/print_test
#!/usr/bin/env python
print('hej världen')
^D
bash$ chmod +x my_project/print_test
bash$ print_test
hej världen
(You might have to hash -r print_test before the last command actually works.)
the python interpreter uses the path variable for only importing the modules.
If you want to run as script, then it will depend on initial path of interpreter.
You can check the current paths by:
import sys
print(sys.path)
for your case, if you want to run "print_test.py" from anywhere, you use it as module.
And append the path like:
sys.path.append('/opt/mssql-tools/bin:/root/my-project')
import print_test #this would execute the script
If you want to do without moduling, can check this: https://www.geeksforgeeks.org/run-python-script-from-anywhere-in-linux/

Change directory from python script for calling shell

I would like to build a python script, which can manipulate the state of it's calling bash shell, especially it's working directory for the beginning.
With os.chdir or os.system("ls ..") you can only change the interpreters path, but how can I apply the comments changes to the scripts caller then?
Thank you for any hint!
You can't do that directly from python, as a child process can never change the environment of its parent process.
But you can create a shell script that you source from your shell, i.e. it runs in the same process, and in that script, you'll call python and use its output as the name of the directory to cd to:
/home/choroba $ cat 1.sh
cd "$(python -c 'print ".."')"
/home/choroba $ . 1.sh
/home $

Running multiple cmds using bat file?

I have been trying to run multiple cmds to execute the same command with different arguments but cmd does not work. Here is the code to run the file
cd\
cd F:\A 5th Semester Data\CN\Project\
start cmd \k python test.py A 5000 configA.txt
The next statements will have B, 5001 configB.txt and so on.
Please Help in this matter.
Best Regards.
File and folder paths containing a space character must be enclosed in double quotes as explained in last paragraph of last help page output by running in a command prompt window cmd /?.
The help explains also parameter /K as used by you to keep the console window open after Windows command interpreter finished execution of python which means after Python finished execution of test.py.
And command CD requires the usage of parameter /D if the drive should be also switched as explained in help output by running in a command prompt window cd /?.
cd /D "F:\A 5th Semester Data\CN\Project"
start cmd /k python test.py A 5000 configA.txt
The help of command START is output on running in a command prompt window start /? which lists and explains also the parameter /Dpath.
So the two lines above could be also written as one-liner:
start "Python Processing" /D"F:\A 5th Semester Data\CN\Project" %SystemRoot%\System32\cmd.exe /K python.exe test.py A 5000 configA.txt
But it looks like what you really need is a batch file containing the lines:
cd /D "F:\A 5th Semester Data\CN\Project"
python.exe test.py A 5000 configA.txt
python.exe test.py B 5001 configB.txt
rem and so on
Or using a FOR loop and an environment variable with delayed expansion:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
cd /D "F:\A 5th Semester Data\CN\Project"
set "Number=5000"
for %%I in (A B C D E) do (
python.exe test.py %%I !Number! config%%I.txt
set /A Number+=1
)
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cd /?
echo /?
endlocal /?
for /?
set /?
setlocal /?

how to give multiple command to cmd.exe after opening it using python [duplicate]

I'm trying to open a new command window in a BAT file:
start %windir%\system32\cmd.exe
After it opens, I'd like to execute a BAT command in the new window:
echo "test in new window"
How can I do this?
You may already find your answer because it was some time ago you asked. But I tried to do something similar when coding ror. I wanted to run "rails server" in a new cmd window so I don't have to open a new cmd and then find my path again.
What I found out was to use the K switch like this:
start cmd /k echo Hello, World!
start before "cmd" will open the application in a new window and "/K" will execute "echo Hello, World!" after the new cmd is up.
You can also use the /C switch for something similar.
start cmd /C pause
This will then execute "pause" but close the window when the command is done. In this case after you pressed a button. I found this useful for "rails server", then when I shutdown my dev server I don't have to close the window after.
Use the following in your batch file:
start cmd.exe /c "more-batch-commands-here"
or
start cmd.exe /k "more-batch-commands-here"
/c Carries out the command
specified by string and then
terminates
/k Carries out the
command specified by string but
remains
Consult the cmd.exe documentation using cmd /? for more details.
The proper formatting of the command string becomes more complicated when using arguments with spaces. See the examples below. Note the nested double quotes in some examples.
Examples:
Run a program and pass a filename parameter:
CMD /c write.exe c:\docs\sample.txt
Run a program and pass a long filename:
CMD /c write.exe "c:\sample documents\sample.txt"
Spaces in program path:
CMD /c ""c:\Program Files\Microsoft Office\Office\Winword.exe""
Spaces in program path + parameters:
CMD /c ""c:\Program Files\demo.cmd"" Parameter1 Param2
CMD /k ""c:\batch files\demo.cmd" "Parameter 1 with space" "Parameter2 with space""
Launch demo1 and demo2:
CMD /c ""c:\Program Files\demo1.cmd" & "c:\Program Files\demo2.cmd""
Source: http://ss64.com/nt/cmd.html
The above answers helped me. But still required some figuring out. Here is an example script I use to start 3 processes for web development. It results in 3 windows staying open, as they need to run continously.
Mongo is globally added to my path, so I don't need to cd like I do for the other two programs. Of course the path to your files will vary, but hopefully this will help.
:: Start MongoDB
start cmd.exe /k "mongod"
:: cd app directory, and start it
cd my-app
start cmd.exe /k "npm run dev"
:: cd to api server, and start that
cd ../my-app-api
start cmd.exe /k "npm run dev"
This is not very easy.
The best approach is to have the part of your script that you want to be executed in a "new window" to be in a separate .bat file. This might be impractical if e.g. you need a lot of state from the rest of your script (variables, etc). One option is to pass any values you need (e.g. dir to operate in) to the batch file:
start cmd.exe stuff.bat %this_dir%
If you have a large amount of state to transmit you might consider generating a batch file at runtime:
set foo=Hello, World
set list_me=%userprofile%
set tmpdir=c:\windows\temp
set tmp=%tmpdir%\tmp.foo
del /q /f "%tmp%"
echo.echo %foo%>>"%tmp%"
echo.dir "%list_me%">>>"%tmp"
start cmd.exe "%tmp%"
del /q /f "%tmp%"
Obviously this is a trivial example.
Thanks to all here in Stack Overflow; this solution solves the above question but is extended to automatically run these tasks:
I want to run my rails server
Run a rake jobs:worker for my delayed_job gem too
and Open default internet browser to show my page
finally, to leave a cmd window open for any extra commands during my session.
I guess my project is called "antiquorum."
Create an "init.bat" file in your %USERPROFILE% directory (open a cmd window and take a look at the path to the left of the cursor to know what %USERPROFILE% is)
#echo off
cd C:/projects/rails3/antiquorum
if "%1" == "antiquorum" GOTO start
if "%1" == "worker" GOTO worker
if "%1" == "server" GOTO server
if "%1" == "" GOTO end
:start
start cmd /k %USERPROFILE%\init.bat worker
start cmd /k %USERPROFILE%\init.bat server
TIMEOUT 30
start "" "http://localhost:3000/"
GOTO end
:server
rails s
GOTO end
:worker
rake jobs:work
:end
In a new command line window type: C:> init antiquorum
The code opens two more cmd windows and a browser. TIMEOUT avoids errors in the browser.
The :start section does the work.
You can run tasks 1,2 or 4 separately by typing params as: server, worker, or none to leave a cmd opened in root of "antiquorum" project.
Enjoy.
Adding /k between two commands executes both command in order.
Example:
cmd /k echo "hello"
this command will first open command prompt then execute echo "hello" command
If I understand you correctly doing this in side your bat file will open Command prompt and print your message to screen.
cmd.exe hello world
hope this helps.
to run a python file in a new cmd window with spaces in the file name:
start cmd.exe /k python "C:\Program Files\HelloWorld.py"
Extending answer from #Dan Zuzevich. Below is CD "Change Directory" if your target file is on different drive. For example it have to call file from drive C and drive D.
:: Start MongoDB
start cmd.exe /k "mongod"
:: cd app directory, and start it
cd C:\project\dev
C:
start cmd.exe /k "npm run dev"
:: cd to api server, and start that
cd D:\api\server
D:
start cmd.exe /k "npm run dev"
I wanted my window to remain open after I killed or restarted Firebase so I used two batch files.
Desktop file for easy access: run_firebase.bat:
--------------START FILE CONTENTS--------------
start cmd /k C:\dev\init_firebase_batch.bat
---------------END FILE CONTENTS---------------
Batch file to run the intended results: C:\dev\init_firebase_batch.bat
--------------START FILE CONTENTS--------------
cd C:\dev\aptr_datasync\aperture-customer-hub
firebase emulators:start
---------------END FILE CONTENTS---------------
So ... double click run_firebase.bat and it runs the second batch. After Ctrl+C out of my process the window remains open. Seems trivial but I don't like distractions while I'm working on code.
I only spent time solving because I thought it would be simple. Hopefully this creates that simplicity for others.
I think this checks off the questions in the initial post:
[x] I'm trying to open a new command window in a BAT file
[x] After it opens, I'd like to execute a BAT command in the new window
I needed to run an environment and then use python while in that environment.
If my folder structure is:
C:\environments>
C:\environments\encrypted_stuff>
C:\environments\encrypted_stuff\p1>
C:\environments\encrypted_stuff\p2>
And I wanted to activate the "encrypted_stuff" environment then call a script from p2, I might type this in a bat that is stored in C:\environments\p2.bat
start cmd /k "Scripts\activate && cd p2 && python p2_script.py"
Then I can have a bat file for any of the scripts and all would use my "encrypted_stuff" environment. Now I can click the bat file from the desktop and it will load my specific environment and then run the script in that environment.

Batch Scripting: Running python script on all directories in a folder

I have a python script called script.py which I would like to run on all of the directories inside of a specific directory. What is the easiest way to do this using batch scripting?
My assumption is some usage of the FOR command, but I can't quite make any leads to solve the problem using the command...
Use the /d operator on for:
for /D %%d in (*) do script.py %%d
This assumes you only need to execute one command per directory (script.py %%d) if you need to execute more use braces (). Also I'm guessing there's an execution engine needed first, but not sure what it is for you.
A multi-line example:
for /D %%d in (%1) do (
echo processing %%d
script.py %%d
)
Building upon Rudu's answer, and assuming script.py is located in the same directory (say C:\Test) as the following batch script, you could also run script.py recursively on all the directories present in C:\Test:
#echo off
for /d /r %%d in (*) do (
echo Processing: %%d
script.py "%%d"
)
The FOR help available from cmd.exe does not seem to mention it supports multiple modifiers, but it works on Windows 7.

Categories

Resources