引号/字符串在 Powershell 中如何工作?

引号/字符串在 Powershell 中如何工作?

我有一个在常规的旧 Windows 命令 Shell 中工作的命令行,但在 Powershell 中却被误解了(我对 Powershell 还很陌生)。

sqlcmd -S .\SQLEXPRESS -i "f:\SQLBackups\ExpressMaint.sql" -v DB="ksuite" -v OPTYPE="DB" -v BACKUPFOLDER="f:\SQLBackups" -v REPORTFOLDER="f:\SQLBackups\Reports" -v DBRETAINUNIT="days" -v DBRETAINVAL="7"

Powershell 似乎正在从需要路径的参数中删除驱动器号。例如,当我尝试在 Powershell 中运行上述命令时,我得到以下信息:

Sqlcmd: ':\SQLBackups': Invalid argument. Enter '-?' for help.

当然,没有驱动器号它是无效的。我尝试过双引号、转义等方法,但都无法正常工作。我错过了 Powershell 的不同之处吗?

答案1

Jaykul 的启动过程也是我这样做的方式。SQLCMD 在设计时考虑了 cmd.exe,因此它想要查看引号字符与 Powershell 使用它们的方式(或者更确切地说不使用它们)之间存在一些冲突。

以下是您可以用来直接拨打电话的方法,应该可以正常工作:

sqlcmd -S .\SQLEXPRESS -i "`""f:\SQLBackups\ExpressMaint.sql`"" -v 'DB="ksuite"' -v 'OPTYPE="DB"' -v 'BACKUPFOLDER="`"'f:\SQLBackups'`"" -v 'REPORTFOLDER="`"'f:\SQLBackups\Reports'`"" -v 'DBRETAINUNIT="days"' -v 'DBRETAINVAL="7"'

答案2

首先,PowerShell 假设所有参数都只是一个值或一-name value对。当值的中间有引号时,就会发生奇怪的事情……

在以下情况下,您很可能只需要引用整个参数:

sqlcmd -S .\SQLEXPRESS -i "f:\SQLBackups\ExpressMaint.sql" -v 'DB="ksuite"' -v 'OPTYPE="DB"' -v 'BACKUPFOLDER="f:\SQLBackups"' -v 'REPORTFOLDER="f:\SQLBackups\Reports"' -v 'DBRETAINUNIT="days"' -v 'DBRETAINVAL="7"'

不过,我通常的建议是使用 Start-Process,它需要全部参数放在一个字符串中,因此您可以执行以下操作:

Start-Process sqlcmd @"
-S .\SQLEXPRESS -i "f:\SQLBackups\ExpressMaint.sql" -v DB="ksuite" -v OPTYPE="DB" -v BACKUPFOLDER="f:\SQLBackups" -v REPORTFOLDER="f:\SQLBackups\Reports" -v DBRETAINUNIT="days" -v DBRETAINVAL="7"
"@ -RedirectStandardOutput f:\SQLBackups\CapturedOutput.log

最后一行-RedirectStandardOutput f:\SQLBackups\CapturedOutput.log只会将标准输出捕获到文件中,以防您需要它...如果您需要记录错误输出,或者需要提供输入,您也可以将它们重定向到/从文件。

答案3

我没有 sqlcmd,所以我无法评论它是如何解释所传递的参数的,但是如果我使用您使用的结构将参数传递给批处理文件,该文件只会回显调用 cmd shell 的命令(echo %cmdcmdline%)显示作为参数传递的内容如下:

cmd /c ""C:\Users\Joe\sqlcmd.cmd"  -S .\SQLEXPRESS -i f:\SQLBackups\ExpressMaint.sql -v DB=ksuite -v OPTYPE=DB -v BACKUPFOLDER=f:\SQLBackups -v REPORTFOLDER=f:\SQLBackups\Reports -v DBRETAINUNIT=days -v DBRETAINVAL=7"

Sqlcmd 的解析器可能不喜欢 Powershell 删除查询位置等某些参数周围的引号的方式,以及数据库=“ksuite”参数发生严重改变。

一个可能有效的选项是将整个内容用单引号引起来,以保留内部的双引号字符串,并希望 sqlcmd 解析器可以处理这个问题:

sqlcmd '-S .\SQLEXPRESS -i "f:\SQLBackups\ExpressMaint.sql" -v DB="ksuite" -v OPTYPE="DB" -v BACKUPFOLDER="f:\SQLBackups" -v REPORTFOLDER="f:\SQLBackups\Reports" -v DBRETAINUNIT="days" -v DBRETAINVAL="7"'

这会将未修改的参数列表传递给 sqlcmd,但就 shell 而言,它是作为单个参数传递的,如果它能起作用,我会感到惊讶。如果您有选择地用单引号引用所有正在修改的参数块,则更有可能成功,如下所示:

sqlcmd.cmd -S .\SQLEXPRESS -i '"f:\SQLBackups\ExpressMaint.sql"' -v 'DB="ksuite"' -v 'OPTYPE="DB"' -v 'BACKUPFOLDER="f:\SQLBackups"' -v 'REPORTFOLDER="f:\SQLBackups\Reports"' -v 'DBRETAINUNIT="days"' -v 'DBRETAINVAL="7"'

如果这仍然不起作用,则可能还有其他项目需要明确转义,而不仅仅是通过使用在 Powershell 字符串解析中用作转义字符的反引号在单引号和双引号之间切换来避免。

help about_quoting您可以从 PowerShell 内部获取有关引用和转义的各个方面的更多信息。

相关内容