Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/382.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Node.js中的引号生成参数_Javascript_Node.js_Tar_Spawn - Fatal编程技术网

Javascript Node.js中的引号生成参数

Javascript Node.js中的引号生成参数,javascript,node.js,tar,spawn,Javascript,Node.js,Tar,Spawn,我在Node.jsspawn参数中使用双引号,因为它们可能包含空格: const excludes = ['/foo/bar', '/foo/baz', '/foo/bar baz']; const tar = spawn('tar', [ '--create', '--gzip', // '--exclude="/foo/bar"', '--exclude="/foo/baz"', '--exclude="/foo/bar baz"' ...excludes.map(exclude

我在Node.js
spawn
参数中使用双引号,因为它们可能包含空格:

const excludes = ['/foo/bar', '/foo/baz', '/foo/bar baz'];
const tar = spawn('tar', [
  '--create', '--gzip',
  // '--exclude="/foo/bar"', '--exclude="/foo/baz"', '--exclude="/foo/bar baz"'
  ...excludes.map(exclude => `--exclude="${exclude}"`),
  '/foo'
], { stdio: ['ignore', 'pipe', 'inherit'] });
出于某种原因,
tar
忽略了
——排除了以这种方式提供的参数。结果与
spawn
require('child_process')。spawn
require('cross-spawn')

--exclude
在不需要双引号的路径中没有双引号时按预期工作

即使使用双引号,shell也能实现同样的效果:

tar --create --gzip --exclude="/foo/bar" --exclude="/foo/baz" /foo > ./foo.tgz

我不确定那里发生了什么,以及如何调试
spawn
,以检查它是否对双引号进行了一些奇怪的转义。

这是引号类型优先级中的一个问题。双引号优先于单引号,因此spawn调用失败

系统shell将去掉参数周围的引号,因此程序将在末尾获取未加引号的值。生成进程会绕过此步骤,因为它会绕过shell,因此程序会将这些文字引号作为参数的一部分,并且不知道如何适当地处理它们

我知道有两种解决方法:

  • 这与直觉相反,但是切换报价类型应该可以解决这个问题。将上述代码切换到:

    const tar = spawn("tar", [
      "--create", "--gzip",
      "--exclude='/foo/bar'", "--exclude='/foo/baz'", "/foo"
    ], { stdio: ["ignore", "pipe", "inherit"] });
    
  • 或者,您可以使用
    {shell:true}
    并使用当前格式。这将通过shell传递spawn请求,因此将发生当前跳过的解析步骤。了解更多有关此的信息


  • 您应该了解shell如何处理空格和引号。我说“外壳”-有不同的外壳,我不知道它们之间的区别,所以我将要写的东西可能不适用于你。有人可以随意编辑,这样更精确

    shell命令中可以包含各种复杂的语法:管道命令、输入和输出文件、插值变量、插值命令、环境变量,以及至少4种(是的,4种)引用字符串的不同方式。但就这个问题而言,让我们假设shell命令是一个命令名,后跟一个字符串参数列表(可能为空)。命令名可以是内置命令(
    cd
    ls
    sudo
    等),也可以是可执行文件。或者,换句话说,shell命令是一个或多个字符串的列表(包括第一个字符串,它告诉shell它是什么类型的命令)

    由于上述复杂因素,有几个字符是特殊字符。这意味着您可能需要使用引号将其转义。然而,引号在语言中引入了大量冗余。例如,以下命令是等效的:

    tar --create --exclude=/foo/bar /foo
    tar --create --exclude='/foo/bar' /foo
    tar --create --exclude="/foo/bar" /foo
    tar --create '--exclude=/foo/bar' /foo
    tar --create "--exclude=/foo/bar" /foo
    
    在每种情况下,命令都是使用参数列表
    --create
    --exclude=/foo/bar
    /foo
    运行可执行文件
    tar

    注意引号的行为,它不同于我所知道的所有其他语言。在大多数语言中,字符串文字完全由一对引号括起来——这就是编译器/解释器如何知道它们的起点和终点。但是在shell命令中,空格告诉shell一个参数的结束位置和下一个参数的开始位置。(引号/转义的空格不计算在内。)引号的唯一用途是改变某些字符的处理方式。Shell命令在这方面非常灵活,因此以下命令也相当于上面的命令:

    tar -"-"create --exc'lude=/fo'o/bar /foo
    tar --cr'eate' --exclude"="/foo"/bar" /foo
    
    当我说这些命令是等效的时,我的意思是
    tar
    可执行文件无法知道调用了哪一个。也就是说,不可能写入可执行文件
    mycommand
    ,使得命令
    mycommand foo
    mycommand“foo”
    将不同的输出写入STDOUT或STDERR,或者返回不同的退出代码,或者以其他方式表现不同

    但是,当从nodejs运行shell命令时,您不需要将shell功能用于管道、文件流、插入变量等,因为如果需要,javascript可以处理所有这些内容。因此,当您向
    spawn
    提供参数时,它会绕过那些shell特性;它对shell特殊字符没有任何作用。您只需直接提供参数。因此,在下面的示例中,其中一个参数是
    --exclude=/foo/bar baz
    ,这将导致
    tar
    忽略
    /foo
    目录中名为
    bar baz
    的文件/目录:

    const tar = spawn('tar', [
      '--create', '--gzip',
      '--exclude=/foo/bar', '--exclude=/foo/baz', '--exclude=/foo/bar baz',
      '/foo'
    ], { stdio: ['ignore', 'pipe', 'inherit'] });
    
    (虽然很明显,如果您使用的是javascript字符串文字,可能需要在javascript级别转义一些字符。)

    乔舒恩的回答我都不喜欢。(1) 甚至对我都不起作用,我很惊讶它对他起作用了——如果它起作用了,那么我就把它看作是nodejs(或者可能是
    tar
    )中的一个bug。(我在Ubuntu 16.04.3 LTS中运行nodejs v6.9.5,GNU tar v1.28。)至于(2),这意味着不必要地将shell字符串处理的所有复杂性引入javascript代码中。正如上面所说:

    注意:如果启用了
    shell
    选项,请不要将未初始化的用户输入传递到此函数。任何包含shell元字符的输入都可用于触发任意命令执行


    就我个人而言,我不知道shell转义的所有复杂之处,因此我不会冒险使用带有不可信输入的
    shell
    选项运行
    spawn

    如果我理解您的要求,您只需要保留默认的shell行为,即剥离引号并将参数作为单个参数传递,即使它有空格

    在这种情况下,您可以执行以下操作:

    spawn(exe, args, { windowsVerbatimArguments: true });
    
    见:

    windowsVerbatimArguments
    在Windows上不引用或转义参数。在Unix上被忽略。这被设置为
    truespawn(exe, args, { windowsVerbatimArguments: true });