如何打印Perl程序的进程号

$ perl -e 'print $$, "\n"' # just use $$

参考:

http://perldoc.perl.org/perlvar.html


Perl

这篇文章: 有用 无用
创建 2017-06-12 06:07:20 / 更新 2017-06-12 06:10:45

Mojo::UserAgent下载大文件的时候,如何打印下载进度

利用 Mojo::Message

#!/usr/bin/env perl
use feature qw(say);
use warnings;

use Mojo::UserAgent;

my $url = "https://cpan.metacpan.org/authors/id/S/SR/SRI/Mojolicious-7.30.tar.gz";
my $ua  = Mojo::UserAgent->new();
my $tx  = $ua->build_tx(GET => $url);
$tx->res->on(progress => sub {
    my $msg = shift;
    return unless my $len = $msg->headers->content_length;
    my $size = $msg->content->progress;
    say 'Progress: ', $size == $len ? 100 : int($size / ($len / 100)), '%';
});
$ua->start($tx);
say($tx->res->code, ' ', $tx->res->message);

利用 Mojo::Content

#!/usr/bin/env perl

use 5.12.0;
use warnings;

use Mojo::UserAgent;

my $url = "https://cpan.metacpan.org/authors/id/S/SR/SRI/Mojolicious-7.30.tar.gz";
my $ua  = Mojo::UserAgent->new();
my $tx  = $ua->build_tx(GET => $url);

$tx->res->content->on(read => sub {
    my $content = shift;
    return unless my $len = $content->headers->content_length;
    my $size = $content->progress;
    say 'Progress: ', $size == $len ? 100 : int($size / ($len / 100)), '%';
});
$ua->start($tx);

say($tx->res->code, ' ', $tx->res->message);

参考:

  1. http://stackoverflow.com/questions/10086592/mojouseragent-get-with-userdefined-callback
  2. https://metacpan.org/pod/Mojo::UserAgent#build_tx
  3. https://metacpan.org/pod/Mojo::Message#progress
  4. https://metacpan.org/pod/Mojo::Content#read

Perl

这篇文章: 有用 无用
创建 2017-04-16 09:25:46 / 更新 2017-04-16 09:25:46

在Perl中捕捉和处理 Signals

通过 %SIG Hash

use strict;
use warnings;

$SIG{INT} = sub {die "Caught a sigint $!"};

sleep(100);

如果运行这个Perl程序,然后再按control-c,就会发送 SIGINT 给Perl程序,然后 $SIG{INT} 对应的方法会捕捉到 SIGINT 信号

通过 sigtrap 指令

sigtrap 是用来更方便的维护 %SIG 的指令

sigtrap 把信号分为3组:

  • normal-signals(HUP, PIPE, INT and TERM)

  • error-signals(ABRT, BUS, EMT, FPE, ILL, QUIT, SEGV, SYS and TRAP)

  • old-interface-signals(ABRT, BUS, EMT, FPE, ILL, PIPE, QUIT, SEGV, SYS, TERM and TRAP)

例如:

use strict;
use warnings;
use sigtrap qw/die normal-signals/;

sleep(100);


use strict;
use warnings;
use sigtrap qw/handler signal_handler normal-signals/;

sub signal_handler {
    die "Caught a signal $!";
}

sleep(100);

关于 signal

The default signal for kill is TERM

control+c will send interrupt signal(SIGINT) to program

参考:

  1. http://perltricks.com/article/37/2013/8/18/Catch-and-Handle-Signals-in-Perl/
  2. https://superuser.com/questions/107543/bash-man-page-kill-pid-vs-kill-9-pid
  3. https://metacpan.org/pod/sigtrap

Perl

这篇文章: 有用 无用
创建 2017-04-16 07:41:41 / 更新 2017-04-16 09:26:18

Perl 如何更改 @INC

  1. 导入PERL5LIB环境变量

    export PERL5LIB=/home/foobar/lib 
    
  2. 在脚本中使用 use lib

    use lib '/home/foobar/code';
    use My::Module;
    

    有些人也这样:

    BEGIN { unshift @INC, "/home/foobar/code" }
    use My::Module;
    
  3. 执行脚本的时候添加 -I(大写i) 选项

    perl -I /home/foobar/code script.pl
    

以上三种方式都会把 /home/foobar/code 添加到 @INC 的第一个元素

那么如何查看 @INC 呢?

perl -V
perl -e 'print join("\n", @INC), "\n"'

方法1是固定添加到系统 @INC, 方法2,3是执行的时候添加到 @INC


Perl

这篇文章: 有用 无用
创建 2017-02-06 06:35:36 / 更新 2017-02-06 07:14:39

MIME 和 Perl

Encode::MIME::Header

Multipurpose Internet Mail Extensions(多用途的网际邮件扩充)

use Encode qw/encode decode/;
$utf8   = decode('MIME-Header', $header);
$header = encode('MIME-Header', $utf8);

This module implements RFC 2047 Mime Header Encoding. There are 3 variant encoding names; MIME-Header , MIME-B and MIME-Q . The difference is described below

            decode()          encode()
----------------------------------------------
MIME-Header Both B and Q      =?UTF-8?B?....?=
MIME-B      B only; Q croaks  =?UTF-8?B?....?=
MIME-Q      Q only; B croaks  =?UTF-8?Q?....?=

代码示例:

use Encode;
use utf8;

my $plain_str = "我爱编程";
my $str = Encode::encode('MIME-Header', $plain_str);
print $str, "\n"; # =?UTF-8?B?5oiR54ix57yW56iL?=

$str = Encode::decode('MIME-Header', $str);
print $str, "\n"; # 我爱编程

代码示例:

use Encode;
use utf8;
use Encode::HanExtra; # 处理gb18030这种编码的, 如果不添加的话, 会报错: "Unknown encoding: gb18030"

my $str = "=?gb18030?B?1tyxqC3A7s6wo6gyMDE2LjEwLjE3o6k=?=";
$str = Encode::decode('MIME-Header', $str);
print $str, "\n";

Perl

这篇文章: 有用 无用
创建 2016-11-14 07:48:44 / 更新 2016-11-14 09:05:47

Perl 中有趣的包

WWW::WebKit

Kossy
Bootylicious

Graph::Easy
Galileo
Net::EmptyPort
Mail::IMAPClient

Params::Validate

Regexp::Common

JSON::MaybeXS

HTTP::BrowserDetect

Net::POP3
Net::IMAP
IO::Socket
Mail::IMAPClient
Email::Valid

Encode::HanExtra
Encode::Guess
Courriel

Image::JpegTran
Image::JpegTran::AutoRotate
Imager::QRCode

HTML::TableExtract

DBIx::Class::Candy
DBIx::Class::Helpers
DBIx::Class::DeploymentHandler
DBIx::Class::Schema::Loader

Class::Tiny
Capture::Tiny
HTTP::Tiny
Path::Tiny

Data::GUID

App::pmuninstall

HTML::Restrict
HTML::Entities
Mojo::Util # html_unescape

experimental

Beam::Minion
Minion::Notifier

Date::Manip
Date::Manip::Examples

Perl

这篇文章: 有用 无用
创建 2016-10-11 10:35:29 / 更新 2017-07-12 09:26:43

Selenium 和 Perl

什么是 Selenium

浏览器自动化测试的工具

WWW::Selenium
Selenium::Remote::Driver
WebDriver::Tiny

http://www.seleniumhq.org/

从 https://sites.google.com/a/chromium.org/chromedriver/downloads 下载 chromedriver
把下载到的 chromedriver 放到 $PATH 目录包含的文件夹里面

Perl Selenium

这篇文章: 有用 无用
创建 2016-04-28 02:20:17 / 更新 2017-02-07 19:58:49

时间

  1. 时间

    1.1) UTC (Coordinated Universal Time) (协调世界时间)

    1.2) GMT (Greenwich Mean Time) (格林威治时间)

    当计算的精确性不到毫秒级别时, UTC 通常被称作 GMT

    1.3) PST (Pacific Time Zone) (太平洋时间) -- 美国西海岸时间

    1.4) DST (Daylight Saving Time) (日光节约时制) -- 就是把表拨快一个小时

  2. 时区

    全世界划分为 24 个时区, 各个时区的时间就是以 UTC 时间为基础"加"或者"减"

  3. 例子

    北京处于东八区, 所以 北京时间 = UTC + 8h

    纽约处于西五区, 所以 纽约时间 = UTC - 5h

    太平洋时间 = UTC - 8h

    但如果是处于日光节约时制, 纽约时间 = UTC - 4h, 北京时间 = UTC + 9h

  4. 时间格式

    1994-11-05T08:15:30-05:00 corresponds to November 5, 1994, 8:15:30 am, US Eastern Standard Time. “这个表示的是美国东海岸时间”

    1994-11-05T13:15:30Z corresponds to the same instant. 这个表示的是“世界时间”


Perl

这篇文章: 有用 无用
创建 2014-09-01 14:16:25 / 更新 2016-06-16 09:28:33

爬虫代理

  1. Transparent 透明

  2. Anonymous 匿名

  3. High anonymity 高度匿名

发出的头

REMOTE_ADDR = 代理服务器 IP

HTTP_VIA = 值为空或无此头

HTTP_X_FORWARDED_FOR = 值为空或无此头

另外,不使用代理时发出的头:

REMOTE_ADDR = 真实源 IP

HTTP_VIA = 值为空或无此头

HTTP_X_FORWARDED_FOR = 值为空或无此头

Perl

这篇文章: 有用 无用
创建 2014-08-20 15:12:38 / 更新 2017-02-07 19:59:03

perl 的 __LINE__, __FILE__, __PACKAGE____SUB__ 符号

__LINE__ 符号返回当前行数。

$. 返回文件句柄最后访问的行数。

__FILE__ 符号返回 __FILE__ 所在的文件名。

$0 返回被执行的程序的名字。

__PACKAGE__ 符号返回当前包名。

__SUB__ 符号返回当前方法的一个引用, 方法之外返回 undef。需要使用 Perl 5.16(或以上版本) 的 use feature qw('current_sub') pragma。


Perl

这篇文章: 有用 无用
创建 2014-08-11 15:08:43 / 更新 2014-08-11 15:36:28

perl 的 __END____DATA__ 符号

__DATA__ 符号告诉 perl 编译器, perl 代码的编译已经完成。

任何在 __DATA__ 符号后面的数据都可以通过 FOOBAR::DATA 这个文件句柄读到, FOOBAR 就是当前包的包名。

在 'main' 包里, __END__ 符号和 __DATA__ 一样, 但是对于别的模块, __END__ 后的数据是无法自动放入DATA句柄中的, 而 __DATA__ 后的数据可以。

例1

#!/usr/bin/perl
use strict;
use warnings;
while ( <DATA> ) {
    print;
}

__DATA__  # 这时候用 __END__ 一样
abc
123
woaini

例2

# 先写个包 FOOBAR.pm
package FOOBAR;
1;
__DATA__ # 这时候如果用 __END__ 就不能通过 FOOBAR::DATA 这个句柄获得其后面的数据
abc
123
woaini

# 写个脚本调用 FOOBAR 这个包
#!/usr/bin/perl
use strict;
use warnings;
use lib './';
use FOOBAR;
while ( <FOOBAR::DATA> ) {
    print;
}

Perl

这篇文章: 有用 无用
创建 2014-08-11 14:32:50 / 更新 2017-02-07 19:59:09

Perl Command-Line Options

-c # compiles the program without runing it.

-M # -Mmodule 和 use module 一样.

例如:

-MLWP::Simple
-MDigest::MD5='md5_hex,md5_base64'

-m # -mmodule 和 use module() 一样, 不会导入 module 默认导入的包.

-n # add loops around your -e code.

$ perl -n -e 'some code' $file

相当于:

LINE:
    while (<>) { 
        #some code 
    }

-p

$ perl -p -e 'some code' $file

相当于:

LINE:
    while (<>) { 
        #some code 
    } continue {
        print or die $!;
    }

假如在 main code loop 之前或之后需要处理代码, 你可以使用 BEGIN 或 END block.

例如:

$ perl -ne 'END {print $t} @w = /(\w+)g; $t += @w' $file

-a # 打开自动分割模式(autosplit mode), 输入会被分割(默认是一个或多个空格分割)成数组并存入 @F

例如:

$ perl -ane 'END {print $t} $t += @F'

-F # 指定分割字符

例如:

$ perl -F'\t' -MData::Dumper -ane 'print Dumper \@F' $file

-l # 自动 chomps 输入, 设置 $\ 等于 $/. $\ 是输出后面加的字符, 默认是空串(empty string). $/ 是读入的分割符, 默认是新行(new line)

例如:

$ perl -le 'print "Hello World"'
$ perl -le 'print for @INC' # 打印出 @INC
$ perl -F':' -MData::Dumper -alne 'print Dumper \@F' /etc/passwd # 对比加 l 和不加 l 的区别
$ perl -lp -e '$_ = $_ . "abc"' $file # 对比加 l 和不加 l 的区别

-i # 把输入文件(源文件)改名(rename), 并且读改名后的文件, 把转化后的记录写入名字是源文件的名字的文件(其实是一种比较有效的覆盖源文件的方法)

例如:

$ perl -i -pe 's/\bPHP\b/Perl/' $file
$ perl -i.bak -pe 's/\bPHP\b/Perl/' $file # 把源文件保存在 "源文件名.bak"
$ 对比 perl -pi -e 's/\bPHP\b/Perl/' $file 和 perl -ip -e 's/\bPHP\b/Perl/' $file # 因为 i 后面可以跟参数, 所以后者无效

Perl

这篇文章: 有用 无用
创建 2014-07-12 00:47:07 / 更新 2017-02-07 19:59:27

在 perl 里什么是 ‘wide character'

Unicode

Unicode 是一个字符集, 用来存储很多字符的一个空间。 一个 character 的序号值被叫做 code point。

计算机以 byte 为单位, 一个 byte 最多表示 256 个 character。

Unicode 有好几种编码方式, 其中 UTF-8 是最常见的。 Unicode 的编码方式是用多个连续的 byte 来存储一个 code point, 通俗的说就是: character。

UTF-8

UTF-8 是一种 Unicode 的编码方式。

UTF-8 对前 128 个code point, 也就是0-127, 处理方式和 ASCII 一样, 一个 byte 存储一个 character。 其他的 characters 用两个或多个 bytes 来存储。

Text strings (character strings)

Text strings 也叫 character strings 或者 Unicode strings, 由 characters 组成。

Binary strings (byte strings)

Binary strings, 或叫 byte strings 由 bytes 组成。

Encoding

Encoding 是从 text 到 binary 的转换。

Decoding

Decoding 是从 binary 到 text 的转换。

Internal format

Perl 有一个 internal format, 是一种 encoding, 用来 encode text strings 以便他们存储在内存里。

Wide character

这个短语用在一个字符的序号值大于 127, 或大于 255, 或任何字符占领的空间超过一个 byte, 和上下文有关。

在 Perl 里, "Wide character in ..." 是由于一个字符的序号值大于 255。 如果没有指定 encoding 层, Perl 会尝试 ISO-8859-1 的 encoding, 如果不行, 便会发出这个 warning, 并且使用 UTF-8 的encoding 输出。

为了避免这个警告, 可以精确的指定 encoding, 例如:

binmode STDOUT, ":encoding(UTF-8)";

参考:

  • perldoc PerlIO

  • perldoc perlrun

  • perldoc perlunitut

  • perldoc perlunifaq


Perl

这篇文章: 有用 无用
创建 2012-12-07 01:38:20 / 更新 2016-11-23 07:20:54

perl 的一些面试题

  1. 列表和数组有什么区别?

数组可以改变length,而列表不可以。数组可以push或者pop,而列表不可以,它是一些值的集合。数组在scalar上下文中返回其length,而列表返回最右边的值,例如:

$scalar = (2,5,7,9); # $scalar 被赋值为 9

2. require 和 use 有什么区别?

Perl 在运行时间执行 "require" 语句。在编译时间执行 "use" 语句,而且会调用加载包的 "import" 方法。下面两段代码一样:

use MODULE qw(import list);

BEGIN {
    require MODULE;
    MODULE->import(import list);
}

更清楚的例子:

use URI::Escape;

my $url = "http://www.amazon.cn";
my $escape = uri_escape($url); # uri_escape 方法默认导入
print $escape, "\n";


require URI::Escape;
URI::Escape->import(uri_escape); # uri_escape 方法需要 import 才导入

my $url = "http://www.amazon.cn";
my $escape = uri_escape($url);
print $escape, "\n";

3. my 和 local 有什么区别?

"local" 仅仅是给全球变量(meaning package)一个临时的值,并不是创建一个local变量。"my" 则表明创建一个私有变量。

在一个方法中,local $x 会给全球变量 $x 一个临时的值,当在这个方法中调用别的方法的时候,别的方法中 $x 会保留这个值。

而 my $x 仅在所在方法中可见。

#!/usr/bin/perl
use strict;
use warnings;
our $x; # 全球变量

$x = "123";

sub foo {
    local $x = "456";
    print "x in sub foo $x\n"; # $x 为 456
    bar(); # 在 foo 中调用 bar
}

sub bar {
    print "x in sub bar $x\n"; # bar 是 foo 调用的,所以 $x 还是 456
}

foo();

print "x in main: $x\n"; # $x 是 123

Perl

这篇文章: 有用 无用
创建 2012-04-25 04:50:17 / 更新 2013-03-23 13:17:03

perl+quotemeta

quotemeta EXPR quotemeta

Returns the value of EXPR with all non-"word" characters backslashed. (That is, all characters not matching "/[A-Za-z_0-9]/" will be preceded by a backslash in the returned string, regardless of any locale settings.) This is the internal function implementing the "\Q" escape in double-quoted strings.

If EXPR is omitted, uses $_.

例子:

my $s = "aab";
my $r = "a.b";
my $r2 = quotemeta $r;
print "ok" if $s =~ /$r/;   # will output "ok"
print "ok2" if $s =~ /$r2/; # won't output "ok2", because $r2 value is "a\.b"

Perl

这篇文章: 有用 无用
创建 2012-02-22 15:08:59 / 更新 2013-03-23 13:02:00

perl 怎样判断字符是否中文

正则表达式:

\p{Script=Han}
\p{Han}
\p{Hani}

3个一样

那么\p{Han}里又是啥呢?

需安装Unicode::Tussle这个模块,使用unichars命令来查看

unichars -ua '\p{Han}'

例子:

#!/usr/bin/perl -w
use strict;
use utf8; # 举例子的用意,这个不可少,匹配字符串utf8 flag需要是on

my $s1 = "人";
print "$s1 match Han\n" if ( $s1 =~ /\p{Han}/ );

my $s2 = "a";
print "$s2 can't match Han\n" if ( $s2 !~ /\p{Han}/ );

Perl

这篇文章: 有用 无用
创建 2012-02-15 05:25:52 / 更新 2013-03-23 12:45:54

You shouldn't use '||' for selecting between two aggregates for assignment.

@a = @b || @c; # this is wrong
@a = scalar(@b) || @c; # really meant this
@a = @b ? @b : @c; # this works fine, though

分析过程:

  1. perl 中的上下文,也就是Context:There are two major contexts: list and scalar. Certain operations return list values in contexts wanting a list, and scalar values otherwise.

  2. perl 的操作符优先级:|| 的优先级大于=

  3. The ||, // and && operators return the last value evaluated。所以,@a = @b || @c 的执行过程是先@b || @c,而@b || @c 又是先执行@b,这时候@b应该是没有list的上下文,所以返回scalar(@b),如果scalar(@b) 为真的话,那么返回值就是scalar(@b) 了,如果为假,就会去执行@c,因为@c 是|| 操作符的最后一个表达式,所以需要考虑@a 这个上下文。

暂且这样理解。


Perl

这篇文章: 有用 无用
创建 2012-02-03 01:26:53 / 更新 2013-03-23 12:42:12

namespace::clean

namespace::clean这个指令将会在当前包编译完成后清除之前声明的或导入的方法。

当前包自己声明的方法在自己内部可以用,但是这个包所生成的类或实例无法使用。

no namespace::clean;后声明的方法,在下次use namespace::clean;后被清除。

可以使用-except来告诉namespace::clean你不想清除的方法,如果你想-except一个方法,可以直接传入方法名,如果你想-except多个方法,你需要使用数组引用。

例子:

package Foo;
use Moose;
use namespace::clean -except => 'meta';
use namespace::clean -except => [qw( method1 method2 )];

Perl

这篇文章: 有用 无用
创建 2012-01-04 15:51:42 / 更新 2013-03-23 12:30:34

Gearman+perl

client.pl

####################
#client.pl
####################

#!/usr/bin/perl -w
use strict;
use Gearman::Client;

my $client = new Gearman::Client;
$client->job_servers('127.0.0.1');

my $time = time;

for ( 1..5 ) {
    $client->dispatch_background('do', $_);
}

print "time cost: " . (time - $time) . " seconds \n";

worker.pl

####################
#worker.pl
####################

#!/usr/bin/perl -w
use strict;
use Gearman::Worker;

my $worker = new Gearman::Worker;
$worker->job_servers('127.0.0.1');
$worker->register_function(do => \&do);
$worker->work while 1;

sub do{
    my $job = shift;
    my $job_id = $job->arg;

    # get job id and do the job
    # xxx

    print "pid: $$, job id: $job_id" . "\n";
}

Perl

这篇文章: 有用 无用
创建 2011-12-28 15:29:49 / 更新 2013-03-23 12:24:56

catalyst+fastcgi+lighttpd

in your lighttpd conf add: fix-root-scriptname => "enable"

write app.psgi file in app root directory

use strict;
use lib './lib';
use app;
my $app = app->psgi_app(@_);

use Plack::Builder;
builder {
    enable "LighttpdScriptNameFix", script_name => "";
    $app;
};

Perl

这篇文章: 有用 无用
创建 2011-12-18 00:20:12 / 更新 2013-03-23 05:37:19