【问题标题】:Running command in perl6, commands that work in shell produce failure when run inside perl6在 perl6 中运行命令,在 shell 中运行的命令在 perl6 中运行时会产生故障
【发布时间】:2019-01-24 16:00:59
【问题描述】:

我正在尝试使用 Perl6 对变量 $cmd 运行一系列 shell 命令,看起来像

databricks jobs run-now --job-id 35 --notebook-params '{"directory": "s3://bucket", "output": "s3://bucket/extension", "sampleID_to_canonical_id_map": "s3://somefile.csv"}'

  1. 将命令拆分为notebook-params 之后的所有内容

我的 $cmd0 = 'databricks 作业现在运行 --job-id 35 --notebook-params '; 我的 $args = "'{\"目录\": \"$in-dir\", \"输出\": \"$out-dir\", \"sampleID_to_canonical_id_map\": \"$map\"}'"; 我的 $run = run $cmd0, $args, :err, :out;

失败。 Databricks 或外壳都没有给出答案。 stdout 和 stderr 为空。

  1. 用空格分割整个命令

    我的@cmd = $cmd.split(/\s+/); 我的 $run = 运行 $cmd, :err, :out

错误:得到了意外的额外参数(“s3://bucket”、“输出”: "s3://bucket/extension", “sampleID_to_canonical_id_map”: "s3://somefile.csv"}'

  1. 以字符串形式提交命令 我的 $cmd = "$cmd0\"$in-dir\", \"output\": \"$out-dir\", \"sampleID_to_canonical_id_map\": \"$map\"}'";

同样,stdout 和 stderr 是空的。退出代码 1。

这是关于 run 如何只能接受数组而不是字符串(我很好奇为什么)

如果我复制并粘贴给 Perl6 的 run 的命令,它在从 shell 给出时可以工作。通过 perl6 给出时它不起作用。这不好,因为我必须执行这个命令数百次。

也许 Perl6 的 shell https://docs.perl6.org/routine/shell 会更好?我没有使用它,因为手册建议run 更安全。我想在Proc 类中同时捕获标准输出和标准错误

编辑:我已经使用shell 运行此程序,但遇到了与我最初发布的内容无关的其他问题。我不确定这是否有资格被回答。我刚决定在 perl5 中使用反引号。是的,反引号已被弃用,但它们可以完成工作。

【问题讨论】:

  • 你为什么在/\s+/上分手? --notebook-params 后面应该跟一个字符串,即''{"directory": "s3://bucket", "output": "s3://bucket/ext...' - 但其中包含空格。所以你在空间上的分裂是一个坏/奇怪的主意。您很可能希望通过使用 shell $cmd 来涉及 shell。
  • 我不明白为什么应该将数组提交给run 而不是字符串的逻辑。这对我来说是 0 意义。你说的我试过了,还是不行。
  • 您的简单化split 破坏了引用的参数'{"directory": ... .csv"}'。这需要在命令行上显示为 一个 参数,而不是多个。
  • @StefanBecker 我也试过了,但失败了
  • 所以你告诉我你已经尝试过my @cmd = ( 'databricks', 'jobs', 'run-now', '--job-id', '35', '--notebook-params', '{"dire... file.csv"}' );(即绕过拆分进行测试),但仍然失败?

标签: raku


【解决方案1】:

我正在尝试运行一系列 shell 命令

要运行 shell 命令,请调用 shell 例程。它将您提供的位置参数(强制转换为单个字符串)传递给您正在运行 P6 程序的系统的外壳。

要在不涉及 shell 的情况下运行命令,请调用 run 例程。第一个位置参数被强制转换为字符串并作为您要运行的程序的文件名传递给操作系统。其余参数与每个参数之间的空格连接在一起形成一个字符串,该字符串作为命令行传递给正在运行的程序。

my $cmd0 = 'databricks jobs run-now --job-id 35 --notebook-params ';

shellrun 都是错误的:

  • shell 只接受一个参数,$cmd0 不完整。

  • run 的第一个参数是由操作系统解释为要运行的程序的文件名的字符串,$cmd0 不是文件名。

因此,在这两种情况下,您都会得到无结果或无意义的结果。

正如你所发现的,你的另外两个实验也以它们自己的方式无效。

这是关于 run 如何只能接受数组而不是字符串(我很好奇为什么)

run 可以接受单个参数。它将作为要运行的程序的名称传递给操作系统。

它可以接受两个参数。第一个是程序名称,第二个是传递给程序的命令行。

它可以接受三个或更多参数。第一个是程序名称,其余的将连接起来形成传递给程序的命令行。 (在某些情况下,这比两个参数形式更方便编码。)

run 也可以接受单个数组。第一个元素是程序名称,其余元素是传递给它的命令行。 (在某些情况下这样做更方便。)

我刚决定在 perl5 中使用反引号。是的,反引号已被弃用,但它们可以完成工作。

反引号会受到code injection 和shell 插值攻击和错误的影响。但是,是的,如果它们有效,它们就会有效。

P6 具有大多数 P5 功能的直接等效项。这包括反引号。 P6 有两种变体:

  • 更安全的 P6 替代反引号是 qxqx 引用构造调用 shell 但不插入 P6 变量,因此它具有与使用带有单引号字符串的 shell 相同的危险级别。

  • qqx 变体直接等效于 P5 反引号或使用带有双引号字符串的 shell,因此它具有相同的安全隐患。

【讨论】:

  • "run 的第一个参数是一个字符串,被操作系统解释为要运行的程序的文件名,$cmd0 不是文件名。"我不知道,这是缺少的关键信息
  • 操作系统都有一个函数调用,调用代码给出一个名称,操作系统关闭并找到并运行该名称的程序。您还可以传递一个传递给程序的字符串,以便它具有输入参数。 P6 run 函数对应于这个原始操作系统级函数,因此具有程序名称,加上零个或多个串联参数。
  • Shell 位于操作系统之上。使用 shell 需要编写一行文本并按下 Enter 键。这只是一个字符串。它可能以程序名称开头,也可能只是一些 shell 代码。所以 P6 shell 例程只需要一个字符串并将其传递给操作系统的默认 shell。 (我相信这是可配置的。)
【解决方案2】:

两个错误:

  • 简单化的split 将最后一个单个参数分割成多个参数
  • 你通过$cmd 运行,而不是@cmd
use strict;

my @cmd = ('/tmp/dummy.sh', '--param1', 'param2 with spaces');
my $run = run @cmd, :err, :out;

print(@cmd ~ "\n");
print("EXIT_CODE:\t" ~ $run.exitcode  ~ "\n");
print("STDOUT:\t"    ~ $run.out.slurp ~ "\n");
print("STDERR:\t"    ~ $run.err.slurp ~ "\n");

输出:

$ cat /tmp/dummy.sh
#!/bin/bash
echo "prog: '$0'"
echo "arg1: '$1'"
echo "arg2: '$2'"
exit 0

$ perl6 dummy.pl
/tmp/dummy.sh --param1 param2 with spaces
EXIT_CODE:      0
STDOUT: prog: '/tmp/dummy.sh'
arg1: '--param1'
arg2: 'param2 with spaces'

STDERR:

如果可以避免将$cmd 生成为单个字符串,我会直接将其生成为@cmd。否则,您将不得不实现处理引用的复杂拆分操作。

【讨论】:

  • 我重新编辑了这个问题,你的建议也失败了:(这是选项#1
  • 从我的示例中可以看出,调用程序接收第二个参数作为 single 参数。所以从 Perl 方面来看,一切都正确完成。
  • 也许你应该用一个虚拟的 shell 脚本替换你的真实程序,就像我的例子一样,并检查你的 Perl 代码是否按预期发送参数。
  • FWIW,use strict 在 Perl 6 中是默认的,所以你不需要指定。
猜你喜欢
  • 2010-09-30
  • 1970-01-01
  • 2015-08-03
  • 2014-06-26
  • 1970-01-01
  • 2014-04-30
  • 2015-10-05
  • 2013-04-16
  • 1970-01-01
相关资源
最近更新 更多