perl脚本中使用eval函数执行可能有异常的操作

perl脚本中有时候执行的操作可能会引发异常,为了直观的说明,这里举一个json反序列化的例子,脚本如下:

#! /usr/bin/perl
use v5.14;
use JSON;
use Data::Dumper;

# 读取json字符串数据
my $json_str = join('', <DATA>);
# 反序列化操作
my $json = from_json($json_str);

say to_json($json, { pretty => 1 });

__DATA__
bad {
   "id" : 1024,
   "desc" : "hello world",
   "other" : {
      "test_null" : null,
      "test_false" : false,
      "test_true" : true
   }
}


在这里插入图片描述

脚本中有意把正确json字符串之前加了几个字符,显然这个json字符串是不符合规范格式的,在git bash中执行这个脚本,结果如下:
在这里插入图片描述

下面用perl的eval函数改造这个脚本:

#! /usr/bin/perl
use v5.14;
use JSON;
use Data::Dumper;

# 读取json字符串数据
my $json_str = join('', <DATA>);
# 反序列化操作
my $json = eval {
	return from_json($json_str);
};

unless (defined $json) {
	say "from_json failed !!!!";
} else {
	say to_json($json, { pretty => 1 });
}

__DATA__
bad {
   "id" : 1024,
   "desc" : "hello world",
   "other" : {
      "test_null" : null,
      "test_false" : false,
      "test_true" : true
   }
}


脚本中用把from_json的操作放在eval函数中,输出结果如下:
在这里插入图片描述
显然,这个结果是可控的,可预期的。比如就可以使用这种方法判断json字符串是否合法,能够正常反序列化的就是合法的,否则就是非法的。eval函数的具体使用可以使用perldoc -f eval查看。

    eval EXPR
    eval BLOCK
    eval    "eval" in all its forms is used to execute a little Perl
            program, trapping any errors encountered so they don't crash the
            calling program.

            Plain "eval" with no argument is just "eval EXPR", where the
            expression is understood to be contained in $_. Thus there are
            only two real "eval" forms; the one with an EXPR is often called
            "string eval". In a string eval, the value of the expression
            (which is itself determined within scalar context) is first
            parsed, and if there were no errors, executed as a block within
            the lexical context of the current Perl program. This form is
            typically used to delay parsing and subsequent execution of the
            text of EXPR until run time. Note that the value is parsed every
            time the "eval" executes.

            The other form is called "block eval". It is less general than
            string eval, but the code within the BLOCK is parsed only once
            (at the same time the code surrounding the "eval" itself was
            parsed) and executed within the context of the current Perl
            program. This form is typically used to trap exceptions more
            efficiently than the first, while also providing the benefit of
            checking the code within BLOCK at compile time. BLOCK is parsed
            and compiled just once. Since errors are trapped, it often is
            used to check if a given feature is available.

            In both forms, the value returned is the value of the last
            expression evaluated inside the mini-program; a return statement
            may also be used, just as with subroutines. The expression
            providing the return value is evaluated in void, scalar, or list
            context, depending on the context of the "eval" itself. See
            "wantarray" for more on how the evaluation context can be
            determined.

            If there is a syntax error or runtime error, or a "die"
            statement is executed, "eval" returns "undef" in scalar context,
            or an empty list in list context, and $@ is set to the error
            message. (Prior to 5.16, a bug caused "undef" to be returned in
            list context for syntax errors, but not for runtime errors.) If
            there was no error, $@ is set to the empty string. A control
            flow operator like "last" or "goto" can bypass the setting of
            $@. Beware that using "eval" neither silences Perl from printing
            warnings to STDERR, nor does it stuff the text of warning
            messages into $@. To do either of those, you have to use the
            $SIG{__WARN__} facility, or turn off warnings inside the BLOCK
            or EXPR using "no warnings 'all'". See "warn", perlvar, and
            warnings.

            Note that, because "eval" traps otherwise-fatal errors, it is
            useful for determining whether a particular feature (such as
            "socket" or "symlink") is implemented. It is also Perl's
            exception-trapping mechanism, where the "die" operator is used
            to raise exceptions.

            Before Perl 5.14, the assignment to $@ occurred before
            restoration of localized variables, which means that for your
            code to run on older versions, a temporary is required if you
            want to mask some, but not all errors:

             # alter $@ on nefarious repugnancy only
             {
                my $e;
                {
                  local $@; # protect existing $@
                  eval { test_repugnancy() };
                  # $@ =~ /nefarious/ and die $@; # Perl 5.14 and higher only
                  $@ =~ /nefarious/ and $e = $@;
                }
                die $e if defined $e
             }

            There are some different considerations for each form:

            String eval
                Since the return value of EXPR is executed as a block within
                the lexical context of the current Perl program, any outer
                lexical variables are visible to it, and any package
                variable settings or subroutine and format definitions
                remain afterwards.

                Under the "unicode_eval" feature
                    If this feature is enabled (which is the default under a
                    "use 5.16" or higher declaration), EXPR is considered to
                    be in the same encoding as the surrounding program. Thus
                    if "use utf8" is in effect, the string will be treated
                    as being UTF-8 encoded. Otherwise, the string is
                    considered to be a sequence of independent bytes. Bytes
                    that correspond to ASCII-range code points will have
                    their normal meanings for operators in the string. The
                    treatment of the other bytes depends on if the
                    "'unicode_strings"" feature is in effect.

                    In a plain "eval" without an EXPR argument, being in
                    "use utf8" or not is irrelevant; the UTF-8ness of $_
                    itself determines the behavior.

                    Any "use utf8" or "no utf8" declarations within the
                    string have no effect, and source filters are forbidden.
                    ("unicode_strings", however, can appear within the
                    string.) See also the "evalbytes" operator, which works
                    properly with source filters.

                    Variables defined outside the "eval" and used inside it
                    retain their original UTF-8ness. Everything inside the
                    string follows the normal rules for a Perl program with
                    the given state of "use utf8".

                Outside the "unicode_eval" feature
                    In this case, the behavior is problematic and is not so
                    easily described. Here are two bugs that cannot easily
                    be fixed without breaking existing programs:

                    *   It can lose track of whether something should be
                        encoded as UTF-8 or not.

                    *   Source filters activated within "eval" leak out into
                        whichever file scope is currently being compiled. To
                        give an example with the CPAN module
                        Semi::Semicolons:

                         BEGIN { eval "use Semi::Semicolons; # not filtered" }
                         # filtered here!

                        "evalbytes" fixes that to work the way one would
                        expect:

                         use feature "evalbytes";
                         BEGIN { evalbytes "use Semi::Semicolons; # filtered" }
                         # not filtered

                Problems can arise if the string expands a scalar containing
                a floating point number. That scalar can expand to letters,
                such as "NaN" or "Infinity"; or, within the scope of a "use
                locale", the decimal point character may be something other
                than a dot (such as a comma). None of these are likely to
                parse as you are likely expecting.

                You should be especially careful to remember what's being
                looked at when:

                    eval $x;        # CASE 1
                    eval "$x";      # CASE 2

                    eval '$x';      # CASE 3
                    eval { $x };    # CASE 4

                    eval "\$$x++";  # CASE 5
                    $$x++;          # CASE 6

                Cases 1 and 2 above behave identically: they run the code
                contained in the variable $x. (Although case 2 has
                misleading double quotes making the reader wonder what else
                might be happening (nothing is).) Cases 3 and 4 likewise
                behave in the same way: they run the code '$x', which does
                nothing but return the value of $x. (Case 4 is preferred for
                purely visual reasons, but it also has the advantage of
                compiling at compile-time instead of at run-time.) Case 5 is
                a place where normally you *would* like to use double
                quotes, except that in this particular situation, you can
                just use symbolic references instead, as in case 6.

                An "eval ''" executed within a subroutine defined in the
                "DB" package doesn't see the usual surrounding lexical
                scope, but rather the scope of the first non-DB piece of
                code that called it. You don't normally need to worry about
                this unless you are writing a Perl debugger.

                The final semicolon, if any, may be omitted from the value
                of EXPR.

            Block eval
                If the code to be executed doesn't vary, you may use the
                eval-BLOCK form to trap run-time errors without incurring
                the penalty of recompiling each time. The error, if any, is
                still returned in $@. Examples:

                    # make divide-by-zero nonfatal
                    eval { $answer = $a / $b; }; warn $@ if $@;

                    # same thing, but less efficient
                    eval '$answer = $a / $b'; warn $@ if $@;

                    # a compile-time error
                    eval { $answer = }; # WRONG

                    # a run-time error
                    eval '$answer =';   # sets $@

                If you want to trap errors when loading an XS module, some
                problems with the binary interface (such as Perl version
                skew) may be fatal even with "eval" unless
                $ENV{PERL_DL_NONLAZY} is set. See perlrun.

                Using the "eval {}" form as an exception trap in libraries
                does have some issues. Due to the current arguably broken
                state of "__DIE__" hooks, you may wish not to trigger any
                "__DIE__" hooks that user code may have installed. You can
                use the "local $SIG{__DIE__}" construct for this purpose, as
                this example shows:

                    # a private exception trap for divide-by-zero
                    eval { local $SIG{'__DIE__'}; $answer = $a / $b; };
                    warn $@ if $@;

                This is especially significant, given that "__DIE__" hooks
                can call "die" again, which has the effect of changing their
                error messages:

                    # __DIE__ hooks may modify error messages
                    {
                       local $SIG{'__DIE__'} =
                              sub { (my $x = $_[0]) =~ s/foo/bar/g; die $x };
                       eval { die "foo lives here" };
                       print $@ if $@;                # prints "bar lives here"
                    }

                Because this promotes action at a distance, this
                counterintuitive behavior may be fixed in a future release.

                "eval BLOCK" does *not* count as a loop, so the loop control
                statements "next", "last", or "redo" cannot be used to leave
                or restart the block.

                The final semicolon, if any, may be omitted from within the
                BLOCK.


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/246679.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringMVC的文件上传、多文件上传

概念&#xff1a;上传/下载应用 对于上传功能&#xff0c;我们在项目中是经常会用到的&#xff0c;比如用户注册的时候&#xff0c;上传用户头像&#xff0c;这个时候就会使用到上传的功能。而对于下载&#xff0c;使用场景也很常见&#xff0c;比如我们项目中有个使用说明是是…

如何提升数据结构方面的算法能力?

谈及为什么需要花时间学算法&#xff0c;我至少可以列举出三个很好的理由。 (1)性能&#xff1a;选择正确的算法可以显著提升应用程序的速度。仅就搜索来说&#xff0c;用二分查找替 换线性搜索就能为我们帶来巨大的收益。 (2)安全性&#xff1a;如果你选用了错误的算法&…

小小手表探索更多 好玩伴也是好帮手

华为儿童手表 5X 不仅是孩子的好玩伴&#xff0c;也是家长的好帮手。全能形态让小小手表探索更多&#xff0c;高清双摄记录美好&#xff0c;离线定位随时掌握&#xff0c;绿色纯净守护成长&#xff0c;让孩子享受科技带来的安全与乐趣。

vue3.0项目搭建

一、安装vue3脚手架 卸载vue2脚手架 npm uninstall -g vue-cli清除缓存 npm cache clen --force安装最新脚手架 npm install -g vue/cli查看脚手架版本 vue -V 二、构建项目 创建项目 vue create 项目名选择配置 自定义配置&#xff0c;回车 上下键选择Linter / Formatter&a…

【超图】SuperMap iClient3D for WebGL/WebGPU ——暴雪

作者&#xff1a;taco 时隔多年北京又开始降下了特大暴雪。身为打工人的你有没有居家办公呢&#xff1f;反正小编我是没有。既然没有借着暴雪的功劳居家办公&#xff0c;那就接着雪来输出一篇博客好了。基于SuperMap iClient3D for WebGL/WebGPU 实现暴雪仿真效果。 先来看下效…

今日最新版早安问候大全,身体健康,平安幸福!

1&#xff0e;只想用不打扰你的方式轻轻地告诉你&#xff0c;我在惦记你。只希望你看到这个短信的时候&#xff0c;嘴角泛起灿烂的一笑!让身边的人知道你是幸福的&#xff0c;看短信的&#xff0c;我在问候你啊。早安~ 2&#xff0e;晨曦在呼叫&#xff0c;鸟儿在鸣叫&#xff…

【Hive】——DDL(TABLE)

1 查询指定表的元数据信息 如果指定了EXTENDED关键字&#xff0c;则它将以Thrift序列化形式显示表的所有元数据。 如果指定了FORMATTED关键字&#xff0c;则它将以表格格式显示元数据。 describe formatted student&#xff1b;2 删除表 如果已配置垃圾桶且未指定PURGE&…

复杂填报逻辑的支持

复杂填报逻辑的支持 一般填报表应用场景分为两种&#xff1a; 旧数据的维护 现有数据存储中已有一些数据&#xff0c;需要人工在页面对数据进行修改维护。 新数据的采集。 现有数据存储中没有数据&#xff0c;需要人工页面填写录入数据。 简单的数据维护与采集&#xff0…

Mysql 的ROW_NUMBER() 和分区函数的使用 PARTITION BY的使用

Mysql 的ROW_NUMBER() 和分区函数的使用 PARTITION BY的使用 描述: 遇到了一个需求,需要查询用户id和计划id,但是人员id的是重复,我想把人员id去重,支取一个。自然而然的就想到了SELECT DISTINCT prj_plan.last_month_user,prj_plan.id FROM prj_funds_plan prj_plan 但是…

Linux arm架构下构建Electron安装包

上篇文章我们介绍 Electron 基本的运行开发与 windows 安装包构建简单流程&#xff0c;这篇文章我们从零到一构建 Linux arm 架构下安装包&#xff0c;实际上 Linux arm 的构建流程&#xff0c;同样适用于 Linux x86 环境&#xff0c;只不过需要各自的环境依赖&#xff0c;Linu…

java中,用函数对象表示策略

简而言之&#xff0c;函数指针的主要用途就是实现策略(Strategy)模式。 Java没有提供函数指针&#xff0c;但是可以用对象引用实现相同的功能。调用对象上的方法通常是执行该对象上某项操作。 在Java中&#xff0c;使用函数对象&#xff08;Function Object&#xff09;表示策…

Elasitcsearch--解决CPU使用率升高

原文网址&#xff1a;Elasitcsearch--解决CPU使用率升高_IT利刃出鞘的博客-CSDN博客 简介 本文介绍如何解决ES导致的CPU使用率升高的问题。 问题描述 线上环境 Elasticsearch CPU 使用率飙升常见问题如下&#xff1a; Elasticsearch 使用线程池来管理并发操作的 CPU 资源。…

Android--Jetpack--Navigation详解

须知少日拏云志&#xff0c;曾许人间第一流 一&#xff0c;定义 Navigation 翻译成中文就是导航的意思。它是谷歌推出的Jetpack的一员&#xff0c;其目的主要就是来管理页面的切换和导航。 Activity 嵌套多个 Fragment 的 UI 架构模式已经非常普遍&#xff0c;但是对 Fragmen…

关于“Python”的核心知识点整理大全21

9.3.2 Python 2.7 中的继承 在Python 2.7中&#xff0c;继承语法稍有不同&#xff0c;ElectricCar类的定义类似于下面这样&#xff1a; class Car(object):def __init__(self, make, model, year):--snip-- class ElectricCar(Car):def __init__(self, make, model, year):supe…

VHDL实验:基于有限状态机实现秒表

题目要求&#xff1a; 利用有限状态机实现实现一个具有启动、停止、清零功能的秒表&#xff0c;显示格式&#xff1a;分&#xff1a;秒&#xff1a;十分秒。启动、停止、清零由一个按键控制&#xff0c;按键按下时&#xff0c;功能按启动、停止、清零顺序循环。 思路分析&…

【NTN 卫星通信】Starlink,卫星互联网的技术革命(一)

1. 什么是Starlink Starlink是由Elon Musk创立的私人太空探索公司SpaceX提供的卫星互联网服务。它旨在为世界上传统互联网服务速度慢或不可用的偏远地区提供价格合理的高速互联网。 为什么Starlink很重要&#xff1f;   Starlink之所以重要&#xff0c;是因为它有可能为数百万…

万能微信在线考试系统:适用于任何行业的在线考试系统 附带完整的搭建教程

互联网技术的发展&#xff0c;线上教育、线上考试逐渐成为主流。特别是在疫情期间&#xff0c;许多传统的线下考试都被迫转为线上。然而&#xff0c;对于许多机构、企业来说&#xff0c;搭建一个稳定、安全的在线考试系统并非易事。这需要专业的技术团队、充足的时间和资源投入…

基于Java SSM框架实现二手交易平台网站系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现二手交易平台网站系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认…

逆向获取某音乐软件的加密(js逆向)

本文仅用于技术交流&#xff0c;不得以危害或者是侵犯他人利益为目的使用文中介绍的代码模块&#xff0c;若有侵权请联系作者更改。 老套路&#xff0c;打开开发者工具&#xff0c;直接开始找到需要的数据位置&#xff0c;然后观察参数&#xff0c;请求头&#xff0c;cookie是…

TypeScript入门实战笔记 -- 04 什么是字面量类型、类型推断、类型拓宽和类型缩小?

&#x1f34d;开发环境 1&#xff1a;使用vscode 新建一个 04.Literal.ts 文件&#xff0c;运行下列示例。 2&#xff1a;执行 tsc 04.Literal.ts --strict --alwaysStrict false --watch 3&#xff1a;安装nodemon( 全局安装npm install -g nodemon ) 检测.js文件变化重启项…