Bash调用windows程序,引用如何工作?

时间:2016-05-09 16:06:33

标签: windows bash cmd cygwin quoting

我正在为我的虚拟机做一些脚本,我正在使用cygwin。我需要设置计算机名称和IP地址。这部分很简单,按顺序:

wmic computersystem where caption=name "vm-01"
netsh interface ip set address "Local Area Connection 2" static 10.155.155.50 255.255.255.0

这在cmd.exe中工作得很好。现在我想从bash执行此操作。我想看看我正在执行的命令,所以我正在使用这个bash函数来执行它:

call() {
    echo "$@"
    $@
}

我以直观的方式尝试了逃避引号:

$ call wmic computersystem where caption=name \"wm-01\"
Executing (\\BOH\ROOT\CIMV2:Win32_ComputerSystem.Name="XXX")->rename()
Method execution successful.
Out Parameters:
instance of __PARAMETERS
{
        ReturnValue = 87;
};

哪个不起作用(不要像我最初那样被“方法执行成功”弄错),错误代码87.

$ call netsh interface ip set address \"Local Area Connection 2\" static 10.155.155.50 255.255.255.0

另一方面,这很有效。

我设法使用

wmic命令解决了这个问题
$ call wmic computersystem where caption=name \'wm-01\'
Executing (\\BOH\ROOT\CIMV2:Win32_ComputerSystem.Name="XXX")->rename()
Method execution successful.
Out Parameters:
instance of __PARAMETERS
{
        ReturnValue = 0;
};

哪个确实有用。我用netsh

尝试了同样的方法
$ call netsh interface ip set address \'Local Area Connection 2\' static 10.155.155.101 255.255.255.0
The filename, directory name, or volume label syntax is incorrect.

没有。我想要了解的是为什么一个命令需要\'而第二个\"

1 个答案:

答案 0 :(得分:2)

在这里要认识到有几件事是重要的:

  • 引用的重要性是到shell ,而不是(通常)到正在启动的命令。在识别命令名称并切换其参数之前,shell会删除对此有意义的引号,但是在所有其他命令行处理之后。

  • 在命令的原始文本中,只有出现的未加引号的引号对于引用来说对shell很重要。特别是,参数扩展引起的引号字符并不特殊 - 它们只代表自己。

  • 虽然shell在执行任何扩展之前将命令行拆分为标记,但它稍后会对扩展命令执行分词。在已识别的引号内发生的扩展受到保护而不受单词拆分的影响,但同样,来自扩展引用的引号不会被识别为特殊引号;他们不能防止分词。

然后考虑这个版本的命令:

call netsh interface ip set address "Local Area Connection 2" static 10.155.155.50 255.255.255.0

bash读取该行,将其拆分为单词,轻松执行扩展,执行单词拆分,然后执行引用删除,从而生成以下单词:

  • 呼叫
  • 的netsh
  • 接口
  • IP
  • 设置
  • 地址
  • Local Area Connection 2
  • 静态
  • 10.155.155.50
  • 255.255.255.0

请注意"本地连接2" (没有引号)是一个单词'。第一个单词' call'是命令,剩下的单词是参数,由$@(以及$*和各个位置参数{{表示1}}, etc 。)在函数$1内。

现在考虑当call()执行命令时会发生什么:它与之前的文字分割大致相同,但在那里,连接名称被分成多个参数,并以这种方式呈现给call()命令。

我相信你已经非常感激,但现在考虑一下你的命令的变化:

netsh

在这种情况下,call netsh interface ip set address \"Local Area Connection 2\" static 10.155.155.50 255.255.255.0 个字符会被转义,因此不会使连接名称成为单个shell字。因此,在达到"之前就分开了。因此,您获得与以前相同的结果,除了call()的两个参数中包含引号字符。

那么解决方案是什么?你已经差不多了。特殊参数netsh$@之间的差异是它们与单词拆分的相互作用。当$*在引号内展开时,对结果不执行单词拆分的规则是一个特殊例外 - 结果在$@的元素之间分开,但不在内分割/ em>他们。主要目的是确切地想要做的事情:将shell的位置参数传递给另一个命令。

换句话说,使用此版本的shell函数:

$@

并使用原始命令行调用它,并使用不带引号的引号。