Linux下Process.Start执行shell命令报"unterminated quoted string"错误排查
问题描述
尝试通过C#代码调用7z解压文件,该命令在Windows系统或直接在shell中运行正常,但通过代码执行时失败,怀疑是命令存在未察觉的差异。
实现代码如下:
//Unpack dump with 7z StringBuilder argument = new($"\"{Config.zipPath}\" x \"{dumpPath}\" -so | \"{Config.zipPath}\" x -y -si -ttar"); foreach (string file in new[] { "vn", "vn_titles" /* and other strings */ }) { argument.Append($" db/{file} db/{file}.header"); } Process.Start(Config.shell, string.Format(Config.arguments, argument)).WaitForExit();
配置文件为key=value格式的键值对,会加载到静态Config类中。Windows下配置如下,可正常运行:
shell=cmd.exe zipPath=C:/Program Files/7-Zip-Zstandard/7z.exe arguments=/C "{0}"
但Linux下配置无法运行:
shell=ash zipPath=7z arguments=-c '{0}'
ash命令执行时报错:
x: line 0: syntax error: unterminated quoted string
已尝试的排查操作
- C#代码本身无错误,仅在需要访问未解压的文件时才出现异常。
Config.shell的值为ashstring.Format(Config.arguments, argument)的结果为-c '"7z" x "dump.tar.zst" -so | "7z" x -y -si -ttar db/vn db/vn.header db/vn_titles db/vn_titles.header db/releases db/releases.header db/releases_titles db/releases_titles.header db/releases_vn db/releases_vn.header db/vn_length_votes db/vn_length_votes.header db/tags db/tags.header db/tags_parents db/tags_parents.header db/tags_vn db/tags_vn.header'- 按上述两点推测,执行的命令应为
ash -c '"7z" x "dump.tar.zst" -so | "7z" x ... ',该命令手动执行可正常工作,因此难以定位问题根源。
非理想的解决方案
knittl提供的方案逻辑上是正确的:无论Windows还是Linux,调用shell时都应传入两个参数——-c(Windows的cmd对应/C)和要执行的命令字符串argument,这是更简单的通用方法,但在Windows下无法生效。
cmd似乎完全不支持/C参数的命令中包含带空格的路径:不加引号会无法识别为单个字符串,加引号则会因引号属于路径的一部分导致路径无效。
powershell无此问题,但-c参数的命令长度限制为256字符,同样无法满足需求。
因此最终解决方案是:通过Environment.OSVersion.Platform检测操作系统,在Unix系统下以字符串数组形式传入参数;在Win32NT系统下利用cmd /C的特殊特性——若命令首字符为",则不会解析整个命令,仅移除首尾的",避免了命令内部的字符转义问题,这也是初始版本能在Windows运行的原因。
内容的提问来源于stack exchange,提问作者Torn
相关产品推荐
相关产品推荐

