一个简单的perl脚本:
#!/usr/bin/perl
$num = `sed "s/\([^ ]*\).*/\1/"`;
print "$num";
$total = `sed "s/[^ ]*\(.*\)/\1/"`;
print "$total";
$div = $num / $total;
print "div = $div \n";
当我运行它时:
$ echo 4 10 | ./test.pl
4 10
Illegal division by zero at ./test.pl line 11.
答案 0 :(得分:3)
看着你的代码,我有点困惑。首先是如何提出这样一个奇怪的想法,第二个是如何工作。
我假设你想要的是解析通过STDIN
发送给Perl的字符串。有一种非常简单且惯用的方法,它不涉及sed
内部反引号的奇怪用法:使用菱形运算符<>
,它是一个从{{1}读取的文件句柄}或STDIN
(文件名参数列表),具体取决于给出的内容。
ARGV
通常情况下,我会use strict;
use warnings; # always use these two pragmas
my $input = <>; # input is the string "4 10"
my ($num, $total) = split ' ', $input; # splitting on whitespace
my $div = $num / $total; # ... etc
从chomp
输入以删除尾随换行符,但由于我们STDIN
在此处的空白处,因此无论如何都会移除换行符。
至于为什么会出现split
错误,这是因为您的illegal division by zero
变量未定义,在数字上下文中使用时转换为数字$total
,例如除法运算符0
。如果您使用过/
,则会出现错误
use warnings
毫无疑问,这会告诉你一些错误是什么。
答案 1 :(得分:2)
您的代码无法按预期工作,因为您不了解Perl中字符串的转义规则,并且因为您对STDIN的继承方式感到困惑。
在双引号字符串中,删除反斜杠会忽略\(
之类的未知转义符。因此:"\(" eq "("
。 \1
通常不是替换运算符,而是八进制转义序列:"\1" eq "\01" && "\1" eq "\x01"
- 它是字符0x01“标题起点”。所以你的第一行与
$num = `sed "s/([^ ]*).*/\x01/"`; # this won't change your input
正如您所看到的,正则表达式实际上是错误的,甚至不符合您的输入。
反引号运算符威胁其内容,就像双引号字符串一样,然后将内容传递给shell。 shell也有逃逸,因此必须经常进行双重逃逸。
shell是通过脚本分叉启动的。子进程继承所有文件描述符,包括STDIN。子进程执行shell,然后执行sed
进程,该进程从STDIN读取所有输入,这仍然与原始脚本的STDIN相同。
现在执行第二个命令时,STDIN为空,sed
打印 nothing 。此时,$total
将包含空字符串。当用作数字时,该字符串被解释为零,从而导致您的错误。
解决方案是停止将Perl视为一个美化的shell,因为Perl不像实际的sh
那样将命令串在一起。要解析您的输入,请使用Perl的内置正则表达式。要阅读输入,请使用builtins,而不是shell惯用语。
首先,使用以下命令启动每个脚本:
use strict;
use warnings;
例如,这迫使我们正确声明所有变量。执行此操作后,运行脚本会发出以下警告和错误:
Argument "" isn't numeric in division (/) at script.pl line 12.
Argument "4 10\n" isn't numeric in division (/) at script.pl line 12.
Illegal division by zero at script.pl line 12.
所以你实际上在计算"4 10 \n" / ""
,而不是你想要的。
要阅读输入,我们使用<>
钻石运算符。然后每一行都登陆$_
默认变量。我们可以使用像/([0-9]+)/
这样的正则表达式来提取数字,但我们宁愿将每一行拆分为空格:
while (<>) {
my ($num, $total) = split;
print $num / $total, "\n";
}
然后我们执行除法,并将结果与换行符一起打印出来。如果您使用任何非古老的perl,您还可以use feature 'say'
启用say
函数:与print
完全相同,但会自动添加换行符。
您可以在命令行中指定它们,而不是通过STDIN等提供参数。命令行参数可通过@ARGV
数组访问。现在:
my ($num, $total) = @ARGV;
say $num / $total;
调用:
$ perl script.pl 4 10
对于某些任务,Perl不是适合的工具。如果要编写shell脚本,请编写实际的shell脚本:
#!/bin/bash
input="4 10"
num=`echo $input | sed 's/\([^ ]*\).*/\1/'`
total=`echo $input | sed 's/[^ ]*\(.*\)/\1/'`
echo `bc <<<"scale = 5; $num / $total"`
答案 2 :(得分:1)
更改这样的代码,答案显而易见:
#!/usr/bin/perl
$num = `sed "s/\([^ ]*\).*/\1/"`;
print "num = $num\n";
$total = `sed "s/[^ ]*\(.*\)/\1/"`;
print "total = $total\n";
$div = $num / $total;
print "div = $div\n";