Reputation: 23548
I have a python script that spits out JSON I'd like to capture with ConvertFrom-Json
. Unfortunately, this script requires that I cd to a different directory before I run it. What's the idiomatic powershell way to do this?
This works:
$q = powershell.exe -Command "cd some\other\dir; python JsonMaker.py | ConvertFrom-Json"
As does this:
$cwd=Get-Location
cd some\other\dir
$q=python JsonMaker.py | ConvertFrom-Json
cd "$cwd"
But changing the current working directory seems dicey to me - what if the python script outputs malformed JSON, will I be left in some\other\dir
?
In the unix shell scripting world, I'd obviously do something like
(cd some/other/dir && python JsonMaker.py) | commandThatUsesJson
or read the input in with $(cd some/other/dir && python JsonMaker.py)
. However, in unix subshells are cheap. In powershell I see a noticeable delay to starting a subshell.
What's the approach long-time Powershell users take to something like this?
Upvotes: 3
Views: 397
Reputation: 200293
python.exe JsonMaker.py
runs as a child process. Changes made to the current directory in a child process don't affect the parent. ConvertFrom-Json
also doesn't affect the current directory. It converts a JSON string to an object representing the JSON data or throws a (non-terminating) error if the JSON string is malformed.
If you want to be on the safe side, run the conversion in a try
block and put the statement to return from the temporary working directory after that block:
try {
$q = python JsonMaker.py | ConvertFrom-Json
} catch {
# error handling (optional)
}
cd "$cwd"
or in a finally
clause:
try {
$q = python JsonMaker.py | ConvertFrom-Json
} catch {
# error handling (optional)
} finally {
cd "$cwd"
}
As others have already mentioned, I'd use Push-Location
and Pop-Location
(or their aliases pushd
and popd
) as a simpler way of changing to a different working directory and returning to the original directory. The cmdlets work similar to the Unix shell commands pushd
and popd
.
I'd also recommend adding the extension to the executable name (to avoid unintentionally running different executable files with the same basename (e.g. python.cmd
or python.com
) and using the call operator (&
). Running the command in a new powershell.exe
process is not necessary, and would also return just a string representation of the object created from the JSON string instead of the object itself, which is probably not what you want.
Modified code:
Push-Location 'D:\some\other\dir'
try {
$q = & python.exe JsonMaker.py | ConvertFrom-Json
} catch {
# error handling (optional)
} finally {
Pop-Location
}
or like this if you want to conditionally run the python script only if changing the directory was successful (thus fully emulating the behavior of &&
):
try {
Push-Location 'D:\some\other\dir' -ErrorAction Stop
$q = & python.exe JsonMaker.py | ConvertFrom-Json
} catch {
# error handling (optional)
} finally {
Pop-Location
}
Upvotes: 0
Reputation: 54881
Your script looks fine to me. Unless ConvertFrom-Json
throws a terminating exception (which I don't think it will), the script will continue and your cd $cwd
line would reutnr you back.
You coulod also use Push-/Pop-Location
, but it's basically just a "pretty" way of doing what you already have. Ex.
#Save location
Push-Location
#Script
Set-Location some\other\dir
python JsonMaker.py | ConvertFrom-Json
#Return to previous location
Pop-Location
Upvotes: 1
Reputation: 18156
I'd probably use pushd/popd:
pushd some\other\dir
$q=python JsonMaker.py | ConvertFrom-Json
popd
Upvotes: 1