如何在perl脚本中使用perl的bc命令?

时间:2015-11-09 05:29:44

标签: perl shell bc

我可以在命令行上执行以下脚本。 回声&#34; 56.8 + 77.7&#34; | bc -l <​​/ p>

我也得到了正确的输出但是当我尝试在我的perl / html脚本中执行相同操作并在浏览器中运行它时失败了。你能指导我出错吗?

package core.framework.zookeeper;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class ZkConnect {
    private ZooKeeper zk;
    private CountDownLatch connSignal = new CountDownLatch(0);

    //host should be 127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002
    public ZooKeeper connect(String host) throws Exception {
        zk = new ZooKeeper(host, 3000, new Watcher() {
            public void process(WatchedEvent event) {
                if (event.getState() == KeeperState.SyncConnected) {
                    connSignal.countDown();
                }
            }
        });
        connSignal.await();
        return zk;
    }

    public void close() throws InterruptedException {
        zk.close();
    }

    public void createNode(String path, byte[] data) throws Exception
    {
        zk.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    public void updateNode(String path, byte[] data) throws Exception
    {
        zk.setData(path, data, zk.exists(path, true).getVersion());
    }

    public void deleteNode(String path) throws Exception
    {
        zk.delete(path,  zk.exists(path, true).getVersion());
    }

    public static void main (String args[]) throws Exception
    {
        ZkConnect connector = new ZkConnect();
        ZooKeeper zk = connector.connect("54.169.132.0,52.74.51.0");
        String newNode = "/deepakDate"+new Date();
        connector.createNode(newNode, new Date().toString().getBytes());
        List<String> zNodes = zk.getChildren("/", true);
        for (String zNode: zNodes)
        {
           System.out.println("ChildrenNode " + zNode);   
        }
        byte[] data = zk.getData(newNode, true, zk.exists(newNode, true));
        System.out.println("GetData before setting");
        for ( byte dataPoint : data)
        {
            System.out.print ((char)dataPoint);
        }

        System.out.println("GetData after setting");
        connector.updateNode(newNode, "Modified data".getBytes());
        data = zk.getData(newNode, true, zk.exists(newNode, true));
        for ( byte dataPoint : data)
        {
            System.out.print ((char)dataPoint);
        }
        connector.deleteNode(newNode);
    }

}

我也尝试使用系统,但似乎没有用。

3 个答案:

答案 0 :(得分:4)

好的,所以bc是一个unix实用程序,可以让你做数学运算。您可以通过qx运算符或反引号执行实用程序命令。

然而,在这种情况下......这是一个坏主意,因为它是a)不必要的,b)存在安全风险。为什么?因为您将用户输入从Web表单传递到shell中,从而为您提供了一系列注入攻击。

为什么不改为:

my $res = 56.8 + 77.7;

虽然你在这里,但你真的应该:

  • 开启use strict;
  • 开启use warnings;
  • 开启"taint"模式。 (向你的shebang线添加-T)。

这将减少通过代码注入发生“坏事”的可能性。当你打开“污点”模式时,它会在“污染”时标记任何用户输入,并且不会让你将它用于某些命令而不先清理它。

作为一个例子 - 想象一下如果有人输入了一个表达式:

4"; rm -rf /; echo "owned 

然后你会得到评价它的反对意见;

echo "4";rm -rf /; echo "owned" | bc -l

我想你可以看到这将是一个坏消息!

所以你真的不应该 - 通过用户输入来执行这样的操作。你也应该对eval非常谨慎。使用正则表达式确保您的操作本质上只是“数学”:

 unless ( $str =~ /[^0-9+-*^/.,_()]/ ) {
     eval ( $str );
 }

(为此目的,也可能存在模块)

或者:

my $eval_str = "5 + bogus; nonsense; here 210";

$eval_str =~ s{[^0-9\+\-\/\=\/]+}{}g;
print $eval_str;

答案 1 :(得分:0)

正如其他人所指出的那样,你可以在Perl中进行计算。无需拨打bc

但是我希望看一下你产生输出的方式。你正在使用大量的print()语句。还有更好的方法。

首先,你的陈述如下:

print "<table border=\"0\">\n";

我知道你为什么会有反斜杠,但它看起来不丑陋吗?出于显而易见的原因,您需要在双引号字符串中转义双引号字符。但对于这样的情况,Perl有qq[...]运算符:

print qq[<table border="0">\n];

qq[...]就像双引号字符串一样,但因为它不使用双引号字符来分隔字符串,所以不需要转义字符串中的双引号字符。请注意,您甚至不需要使用[...]来分隔字符串。您几乎可以使用任何字符 - qq(...)qq|...|以及许多其他选项。

其次,为什么每行都有一个单独的print()语句。什么不将它们组合成一个print()语句?

print qq[Content-Type: text/html

<html><body>
<b>Calculator:</b><br/>
<form action="/cgi-bin/calc.cgi" method="GET">
<table border="0">
<tr><td align="right">Expression:</td>
<td><input type="text" name="exp"
 value="$exp"/></td></tr>
<tr><td align="right">Result:</td>
<td>$res</td></tr>
<tr><td></td>
<td><input type="submit" value="Evaluate"/></td></tr>
</table></form>
</html></body>];

请注意如何丢失所有显式\n并将其替换为字符串中嵌入的实际换行符。那看起来不整洁吗?

事实上,大多数Perl程序员都会更进一步,并使用“heredoc”:

print <<"ENDHTML";
Content-Type: text/html

<html><body>
<b>Calculator:</b><br/>
<form action="/cgi-bin/calc.cgi" method="GET">
<table border="0">
<tr><td align="right">Expression:</td>
<td><input type="text" name="exp"
 value="$exp"/></td></tr>
<tr><td align="right">Result:</td>
<td>$res</td></tr>
<tr><td></td>
<td><input type="submit" value="Evaluate"/></td></tr>
</table></form>
</html></body>
ENDHTML

另外,请考虑使用CGI模块的header()方法创建Content-Type标头。

最后,您可以查看CGI::Alternatives以了解如何将所有HTML移到单独的文件中。

答案 2 :(得分:0)

IPC :: Run3和IPC :: Run可以轻松地为子进程提供输入和收集输出。

use IPC::Run3 qw( run3 );

my $equation = '56.8 + 77.7';

run3([ 'bc', '-l' ], $equation, \my $stdout, \my $stderr);

这种方法的好处:

  • 不涉及shell,避免了意外shell代码注入的可能性。

  • Perl的eval并未涉及,这避免了意外Perl代码注入的可能性。

  • 无需编写自己的方程解析器。