16

搜索了这个,似乎找不到已经问过的人,所以就这样吧。

我开始切换到 IPython 作为 Windows 7 上的首选 shell,我想对其进行配置,以便将!cmd命令传递给系统 shell 的 bang magic ( ) 使用 PowerShell 而不是 cmd.exe,这样我就可以利用 MS 所做的增强,但不必将我的更改%COMSPEC%为 PowerShell(我的公司仍然使用几个基于 CMD 的 .BAT 进行自动化,我不想破坏这些)。

我将在顶部发布我的问题,因为答案可能不需要以下任何信息:

  1. 我错过了什么吗?有没有办法在 IPython 中使用配置文件来指定系统命令解释器?
  2. 如果!1,有没有一种方法可以让我在 PowerShell 中使用该进程本地的机器范围环境变量启动子进程?

调查/测试

查看 IPython 代码,我看到它os.system()用于将命令发送到 shell,而不是subprocess.call(). 这使事情变得更加复杂,因为 os.system* 只使用 COMSPEC,而使用 subprocess*,您可以指定要使用的可执行文件。

我尝试加载 PowerShell,设置$env:comspec变量,然后从该 shell 中启动 IPython,但即使 COMSPEC 出现设置,即使在 IPython 中,看起来 CMD 仍在使用:

[PS] C:\> $env:comspec
C:\Windows\system32\cmd.exe
[PS] C:\> $env:comspec = 'powershell.exe'
[PS] C:\> $env:comspec
powershell.exe
[PS] C:\> & 'C:\Python33\Scripts\ipython3.exe'
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)]
Type "copyright", "credits" or "license" for more information.

IPython 1.1.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import os; os.getenv('comspec')
Out[1]: 'powershell.exe'

In [2]: !gci
'gci' is not recognized as an internal or external command,
operable program or batch file.

In [3]: os.system('gci')
'gci' is not recognized as an internal or external command,
operable program or batch file.
Out[3]: 1

看起来本地修改的 COMSPEC 正在传递给 IPython(作为进行本地更改的 PowerShell 进程的子进程),但os.system看起来仍在使用持久设置。

我尝试了类似的方法,使用[Environment]::SetEnvironmentVariable("ComSpec", 'powershell.exe', [System.EnvironmentVariableTarget]::User),以防我只更改用户范围的环境变量就可以逃脱,但这也不起作用(与上面的结果相同 -os.getenv('ComSpec')显示 powershell,但是 !-ed 命令被发送到 CMD) .

由于前面提到的原因,更改机器范围环境变量似乎可以满足我的要求,但对我来说不是一个有效的解决方案。

[PS] C:\> $env:comspec
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe
[PS] C:\> [Environment]::GetEnvironmentVariable('ComSpec','User')
[PS] C:\> [Environment]::GetEnvironmentVariable('ComSpec','Machine')
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe
[PS] C:\> & 'C:\Python33\Scripts\ipython3.exe'
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)]
Type "copyright", "credits" or "license" for more information.

IPython 1.1.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: !gci env:ComSpec

Name                           Value
----                           -----
ComSpec                        C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe

由于这不是一个可行的持续解决方案,我通过修改 ConEmu* 中的设置进行了更多测试。通过在Settings > Startup > ComSpec中将Explicit 可执行文件Set ComSpec 环境变量设置为子进程的选定值* 标志,并提供 powershell.exe 的路径,我能够在不更改全局变量的情况下做到这一点,但我不是确定这是否会对使用 ConEmu 打开的 CMD 控制台产生负面影响,因为该设置是全局的(在 ConEmu 内)。这就是让我问上面的问题 2 的原因,因为我不确定如何在 PowerShell 中设置进程/子本地、机器范围的环境变量(如果这样的话甚至可能的话)。

最后,我的梦想目标是让 IPython 通过配置文件支持命令 shell 解释器的规范,但要做到这一点,os.system()不能使用。我打算subprocess.call()在我的本地副本(a'la this Python Doc)中修改它以进行测试,但是如果有人已经玩过它,或者当前模型是否有足够的优势而不是使用subprocess它我不是知道,我很高兴听到它。看起来这已经在非 Windows 系统 ( GitHub ) 上完成了,但是我对这种规模的 Python 还很陌生,我不能肯定地说,如果在 Windows 端使用这种更改,其他任何东西都不会破坏的条件,以及。

脚注

呸!显然,必须拥有 10 多个声誉才能正确记录问题。以下是我不允许在上面发布的链接:

  • os.system - docs.python.org/3.3/library/os.html#os.system
  • 子进程 - docs.python.org/3.3/library/subprocess.html
  • ConEmu - code.google.com/p/conemu-maximus5/
4

3 回答 3

14

您可以使用 IPython 的脚本魔法来执行 PowerShell 命令。

定义魔法

在您的IPython 配置文件中,修改ipython_config.py以包含以下行:

c.ScriptMagics.script_magics = ['powershell']
c.ScriptMagics.script_paths = {
        'powershell':'powershell.exe -noprofile -command -'}

-command -告诉 PowerShell 将标准输入文本作为命令执行。-noprofile如果您需要加载您的 PS 配置文件,您可以省略,但它会更慢。

然后你可以使用%%powershell作为脚本的单元格魔法

In [1]: %%powershell
   ...: 1..5
1
2
3
4
5

自定义魔法

为了使它更易于使用,我定义了自己的魔法函数来处理带有行和单元魔法的 PowerShell 命令。(见:定义你自己的魔法)这可以通过将脚本放在你的 IPython 配置文件的启动文件夹中来自动加载。(即~\.ipython\profile_default\startup\05-powershell_magic.py

from IPython.core.magic import register_line_cell_magic

from IPython import get_ipython
ipython = get_ipython()

@register_line_cell_magic
def ps(line, cell=None):
    "Magic that works both as %ps and as %%ps" 
    if cell is None:
        ipython.run_cell_magic('powershell', '--out posh_output' ,line)
        return posh_output.splitlines()
    else:
        return ipython.run_cell_magic('powershell', line, cell)

使用示例

要使用%psline magic 并将输出返回到变量:

In [1]: ps_version = %ps $PSVersionTable.PSVersion.ToString()

In [2]: print(ps_version)
['2.0']

要使用%%ps单元格魔法并输出到控制台:

In [3]: %%ps
   ...: gci c:\

    Directory: C:\

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d-r--         10/2/2013  10:39 AM            Program Files
d-r--         12/6/2013   1:44 PM            Program Files (x86)
d----          2/6/2014   4:33 PM            TEMP
d-r--        11/27/2013  11:10 AM            Users
d----         1/13/2014  11:21 AM            Windows

细胞魔法可以将输出发送到一个变量--out <variable name>

In [4]: %%ps --out process_name_id
   ...: $procs = gps| select Name, ID
   ...: $procs| ConvertTo-Csv -NoType| select -skip 1

In [5]: import csv

In [6]: list(csv.reader(process_name_id.splitlines()))
Out[6]:
[['7+ Taskbar Numberer', '3400'],
 ['acrotray', '3668'],
 ['armsvc', '1772'],
 ['audiodg', '4160'],
 ['AutoHotkeyU64', '472'],
 ['chrome', '6276'],
 ...
于 2014-02-07T22:26:03.820 回答
9

comspec最简单的方法是在 Jupiter notebook 或 python shell中导入 os 并更新环境变量

import os
os.environ['comspec']='powershell.exe'
os.getenv('comspec')

然后使用以下命令。

!gc log.txt | select -first 10 # head
!gc -TotalCount 10 log.txt     # also head
!gc log.txt | select -last 10  # tail
!gc -Tail 10 log.txt           # also tail (since PSv3), also much faster than above option
!gc log.txt | more             # or less if you have it installed
!gc log.txt | %{ $_ -replace '\d+', '($0)' }         # sed

以及更多https://ss64.com/ps/

于 2019-05-12T06:16:33.357 回答
0

这有点狡猾,但您可以诉诸使用调用预制的 powershell 脚本

os.system('powershell C:\file.ps1')

或像这样的单个命令:

os.system("powershell; gci | where {$_.Fullname -contains 'some stuff'}")

编辑:

我刚刚对此进行了测试,似乎只需要打开一个 powershell 实例:

os.system("powershell; gci; gc C:\windows\system32\drivers\etc\services; [system.net.dns]::gethostbyaddress('203.20.74.6') | more")

但我想如果你不得不在脚本中多次调用这种类型的东西,它可能会变得丑陋和缓慢。

于 2013-11-13T00:35:55.753 回答