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

Bash调用windows程序,引用是如何工作的?,windows,bash,cmd,cygwin,quoting,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函数

我正在为我的虚拟机编写脚本,我正在使用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.

但事实并非如此。我试图理解的是,为什么一个命令需要
\'
,而第二个命令需要
\“

这里有几点需要注意:

  • 引号的意义在于shell,而不是(通常)正在启动的命令。shell在标识命令名和传递其参数之前,但在所有其他命令行处理之后,删除对该目的有意义的引号

  • 命令的原始文本中只有不带引号的引号对shell来说才是重要的引号。特别是,参数扩展产生的引号字符并不特殊——它们只是表示它们自己

  • 尽管shell在执行任何扩展之前会将命令行拆分为标记,但随后会对扩展的命令执行分词。在可识别引号内进行的扩展可以防止分词,但是,由于扩展而产生的引号不会被识别为特殊引号;它们不会防止分词我很生气

那么,请考虑以下命令版本:

call netsh interface ip set address "Local Area Connection 2" static 10.155.155.50 255.255.255.0
call netsh interface ip set address \"Local Area Connection 2\" static 10.155.155.50 255.255.255.0
bash
读取行,将其拆分为单词,执行简单的扩展,执行单词拆分,然后执行引号删除,从而生成以下单词:

  • 召唤
  • netsh
  • 接口
  • 知识产权
  • 设置
  • 地址
  • 本地连接2
  • 静止的
  • 10.155.155.50
  • 255.255.255.0
请注意,“局域网连接2”(不带引号)是一个“字”。第一个字“call”是命令,其余的字是参数,由函数
call()
中的
$$*
和各个位置参数
$1
等表示

现在考虑当代码> CALL()/代码>绕过执行命令时会发生什么:它与前面一样,直到字拆分,但是在那里,连接名被分成多个参数,并以这种方式呈现给<代码> NETSH < /C>命令。< /P> 我确信你已经很感激了,但是现在考虑一下你的命令的变化:

call netsh interface ip set address "Local Area Connection 2" static 10.155.155.50 255.255.255.0
call netsh interface ip set address \"Local Area Connection 2\" static 10.155.155.50 255.255.255.0
在这种情况下,
字符将被转义,因此不能用于将连接名称作为单个shell字。因此,即使在到达
call()
之前,它也会被拆分。因此,除了
netsh
的两个参数中有引号字符外,您将得到与前面相同的结果

那么解决办法是什么呢?你差不多已经拿到了。特殊参数
$@
$*
之间的区别在于它们与分词的交互作用。当
$@
在引号内展开时,不在结果上执行分词的规则是一个特殊的例外——结果在
$@
的元素之间分割,但不在它们内部。主要目的正是为了完成您正试图做的事情:将shell的位置参数传递给另一个命令

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

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

然后用你原来的命令行调用它,用不带引号的引号。

愚蠢的问题,但是你用不带引号的引号试过了吗?你可以用单引号括住双引号:
““Local Area Connection 2”
,或者只用单引号:
“Local Area Connection 2”
。ups,我把我的问题搞糟了,忘了包括我逃避的原因。我将它传递到bash函数中,然后该函数调用它。请看更新的问题:)对不起,伙计们:/你们说的是批处理?我说的是bash,请看标签,里面有一个
cygwin
,我不知道
“$@”
,它真的很有用,谢谢!)