【问题标题】:shell errors running php exec运行 php exec 的 shell 错误
【发布时间】:2019-01-04 20:53:28
【问题描述】:

我有一个 PHP 脚本,它执行一个 shell 命令来查找给定的两个文件之间的共同项目。这是我的 PHP 脚本的开始:

$E7Bonded_File = "/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv";
$E7Single_File = "/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv";
$E7Common_File = "/opt/IBM/custom/NAC_Dslam/junk/Common_tn_SingleBonded_E7_cust_stats.csv";
//only do this once, with old single/bonded filenames. This will be a list to add to the existing Common file.
exec ("comm -12 <(cut -d ',' -f2 $E7Single_File| sort) <(cut -d ',' -f2 $E7Bonded_File| sort)", $outputCommon); 

我在运行脚本时看到此错误消息:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `comm -12 <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv| sort)'

我检查了,括号对于我的exec() 行看起来没问题。

当我在命令行运行 shell 命令时,它会返回我期望的数字列表:

 comm -12 <(cut -d ',' -f2 junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 junk/PortParameter_E7_Bonded_cust_stats.csv| sort)

我上网查了一下,我似乎正确地使用了exec()。我希望将返回的数字存储为数组$outputCommon

对这个错误信息有什么想法吗?

*********更新答案***************

我的解决方案最终是 mario 和 miken32/我的同事的组合

  1. 在我的 php 脚本顶部添加 #!/bin/bash,然后
  2. 添加/bin/bash -c如下:

    exec("/bin/bash -c /opt/IBM/custom/NAC_Dslam/Common_list.sh", $outputShell);

  3. 将 comm 部分移至 shell 脚本后:

Common_list.sh:

#!/bin/bash
 comm -12 <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 /opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv| sort)

【问题讨论】:

  • 您使用哪个shell进行测试,哪个链接为/bin/sh? dash 不支持表达式管道 AFAIK。
  • 我在命令行中执行了“which sh”,它返回了 /bin/sh。我将此行添加到我的脚本中, exec("which sh",$throwaway); var_dump($throwaway);它也返回了 /bin/sh 。我之前在 php exec 中执行的命令中使用了管道。
  • 问题是否特定于comm?还是Linux?还要检查“shell”标签的描述。也就是说,您的问题是题外话,因为它确实缺少minimal reproducible example

标签: php shell sh


【解决方案1】:

此错误通常出现在不支持 &lt;() 表达式管道的非 bash shell 中。

  • 在 Ubuntu/Debian 服务器上,默认的 /bin/sh 通常是 dash

  • 检查符号链接的二进制文件:

    me@snip:~$ ls -l /bin/sh
    lrwxrwxrwx 1 root root 4 Jul 16  2017 /bin/sh -> dash
    
  • 或者正如@theotherguy 所提到的,当以sh 启动时,bash 以restricted_shell 运行。

  • 请参阅 $_ENV[SHELL],了解 Apache/PHP 默认使用的内容。更改环境变量。

  • 要么适应它,要么用/bin/bash -c '…' 包装shell_exec cmdline。

【讨论】:

  • 您的意思是在上面输入“破折号”吗?
  • mario-我不清楚你在回答中所说的话我需要做什么。
  • 即使sh 是 bash,它也会在进程替换不可用的情况下以更兼容的方式运行
  • @thatotherguy 所以它只适用于真正的登录或交互式shell? // 那么-l+o restricted 可能是必要的。
  • 不,在非交互式 shell 中没问题。它只要求bash 被调用为bash,例如bash -c
【解决方案2】:

可能最简单的解决方案是将其变成服务器上的可执行脚本:

#!/bin/bash
if [[ ! -r "$1" ]] || [[ ! -r "$2" ]]; then
    printf "File not found\n" >&2
    exit 1
fi

comm -12 <(cut -d ',' -f2 "$1"| sort) <(cut -d ',' -f2 "$2"| sort)

然后从 PHP 中调用它:

$E7Bonded_File = escapeshellarg("/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Bonded_cust_stats.csv");
$E7Single_File = escapeshellarg("/opt/IBM/custom/NAC_Dslam/junk/PortParameter_E7_Single_cust_stats.csv");

//only do this once, with old single/bonded filenames. This will be a list to add to the existing Common file.
exec ("/usr/local/bin/your_script.sh $E7Single_File $E7Bonded_File", $outputCommon); 

始终使用 escapeshellarg() 转义您的 shell 参数,即使您认为它们是安全的。

【讨论】:

  • 我试过了,用命令运行 shell 脚本也有同样的问题。这很奇怪,因为命令在命令行运行。
  • 我觉得这很难相信,因为 shebang 告诉它在 bash 下运行。您是否将脚本标记为可执行文件?
  • 是的,我将其设为 chmod 777。我有一些工作要做。我像你一样将 comm 部分移到了 shell 脚本中,顶部是 bin bash,然后我从我的 php 脚本中运行这样的 shell 脚本: exec("/bin/bash -c /opt/IBM/custom/NAC_Dslam /Common_list.sh", $outputShell);我的 php 脚本顶部还有 #!/bin/bash。
  • 顺便说一句,shell 脚本是从命令行运行的,而不是在我进行这些更改之前从 php 脚本运行的。
  • 在我的 exec 前面添加 /bin/bash/ -c 似乎有帮助
【解决方案3】:

使用linter 检查脚本时,它会抱怨:

comm -12 <(cut -d ',' -f2 junk/PortParameter_E7_Single_cust_stats.csv| sort) <(cut -d ',' -f2 junk/PortParameter_E7_Bonded_cust_stats.csv| sort)
     ^-- SC2039: In POSIX sh, process substitution is undefined.

当我定义 shebang #!/bin/sh 时会发生这种情况,而 #!/bin/bash 不会抱怨......因此答案可能是使用 /usr/bin/bash 运行脚本。 escapeshellarg()确实有用。

...

试试shell_exec(),因为exec() 不应该调用任何shell。一个将输出作为字符串返回,另一个可以返回一个数组。 或者,您可以使用 exec() 显式调用 bash:

exec('/bin/bash -c "  command  "', $stdOut);

【讨论】:

  • 您是说使用#!/usr/bin/bash 将comm 命令作为shell 脚本运行。我现在正在尝试,当从我的 php 脚本执行时,它有同样的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多