Perl编程实践:文件操作与命令模拟

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

26、修改程序以包含所有文件,而不仅仅是不以点开头的文件。

若要修改程序以包含所有文件,而不跳过以点开头的文件,可移除代码中跳过点文件的逻辑。

例如在以下代码里:


opendir my $somedir, $dirname or die "Cannot open $dirname: $!";
while (my $name = readdir $somedir) {
    next if $name =~ /^./;                 # skip over dot files
    $name = "$dirname/$name";               # patch up the path
    next unless -f $name and -r $name;      # only readable files
    ...
}

可去掉
next if $name =~ /^./;
这一行,修改后的代码如下:


opendir my $somedir, $dirname or die "Cannot open $dirname: $!";
while (my $name = readdir $somedir) {
    $name = "$dirname/$name";               # patch up the path
    next unless -f $name and -r $name;      # only readable files
    ...
}

这样程序就会包含所有文件,而不跳过以点开头的文件。

27、编写一个程序,其功能类似于
rm
命令,用于删除命令行中指定的任何文件。(你无需处理
rm
的任何选项)

可以使用Perl语言编写如下程序:


#!/usr/bin/perl
use strict;
use warnings;

# 获取命令行参数中的文件名列表
my @files = @ARGV;

# 使用unlink操作符删除文件
unlink @files;

将上述代码保存为一个
.pl
文件,例如
rm_like.pl
,然后在命令行中运行
perl rm_like.pl file1 file2 ...
即可删除指定的文件。

28、编写一个程序,其功能类似于
mv
命令,将第一个命令行参数重命名为第二个命令行参数。(你不需要处理
mv
的任何选项或额外参数。)请记住要考虑目标可能是一个目录的情况;如果是目录,则在新目录中使用相同的原始基本名称。


use File::Basename;
use File::Spec;

my ($source, $dest) = @ARGV;

if (-d $dest) {
    my $basename = basename $source;
    $dest = File::Spec->catfile($dest, $basename);
}

rename $source, $dest or die "Can't rename '$source' to '$dest': $!
";

29、编写一个程序,读入一个数字列表并对其进行数值排序,将排序后的列表以右对齐的列形式输出。用以下示例数据进行测试:17 1000 04 1.50 3.14159 –10 1.5 4 2001 90210 666

以下是实现该功能的 Perl 代码:


#!/usr/bin/perl
use strict;
use warnings;

# 读取输入的数字列表
my @numbers;
while (<>) {
    push @numbers, split;
}

# 定义数值排序子程序
sub by_number {
    $a <=> $b
}

# 对数字列表进行数值排序
my @sorted_numbers = sort by_number @numbers;

# 输出排序后的数字,以右对齐的列形式
foreach my $number (@sorted_numbers) {
    printf "%20g
", $number;
}

将上述代码保存为一个
.pl
文件,例如
sort_numbers.pl
,然后在终端中运行以下命令并输入示例数据:


perl sort_numbers.pl
17 1000 04 1.50 3.14159 -10 1.5 4 2001 90210 666


Ctrl + D
(在 Windows 上按
Ctrl + Z
)结束输入,程序将输出排序后的数字列表,以右对齐的列形式显示。

30、编写一个程序,在给定的字符串中查找给定子字符串的每一次出现,并打印出子字符串所在的位置。例如,给定输入字符串 “This is a test.” 和子字符串 “is”,程序应报告位置 2 和 5。如果子字符串是 “a”,则应报告 8。如果子字符串是 “t”,程序应报告哪些位置?

程序应报告位置 0、10 和 13

31、使用
given
和智能匹配,编写一个程序,报告你在命令行中指定的数字的所有因数(除了 1 和该数字本身)。例如,对于数字 99,你的程序应该报告它能被 3、9、11 和 33 整除。如果该数字是质数(没有因数),则报告该数字是质数。如果命令行参数不是数字,报告错误并且不要尝试计算因数。尽管你可以使用
if
结构和普通匹配来完成这个任务,但只能使用智能匹配。


use 5.010;

say "Checking the number <$ARGV[0]>";
given( $ARGV[0] ) {
    when( ! /Ad+/ ) {
        say "Not a number!"
    }
    my @divisors = divisors( $_ );
    my @empty;
    when( @divisors ~~ @empty ) {
        say "Number is prime"
    }
    default {
        say "$_ is divisible by @divisors"
    }
}

sub divisors {
    my $number = shift;
    my @divisors = ();
    foreach my $divisor ( 2 .. $number/2 ) {
        push @divisors, $divisor unless $number % $divisor;
    }
    return @divisors;
}

32、编写一个程序,接收一个数字作为输入,报告该数字是奇数还是偶数、该数字是否为质数(除了 1 和它本身没有其他约数),以及该数字是否能被你喜欢的数字(假设你喜欢的数字为 42)整除。仅使用智能匹配。


use 5.010;

say "Checking the number <$ARGV[0]>";
my $favorite = 42;

given( $ARGV[0] ) {
    when( ! /Ad+/ ) {
        say "Not a number!"
    }
    my @divisors = divisors( $ARGV[0] );
    when( @divisors ~~ 2 ) {
        # 2 is in @divisors
        say "$_ is even";
        continue;
    }
    when( !( @divisors ~~ 2 ) ) {
        # 2 isn't in @divisors
        say "$_ is odd";
        continue;
    }
    when( @divisors ~~ $favorite ) {
        say "$_ is divisible by my favorite number";
        continue;
    }
    when( $favorite ) {
        # $_ ~~ $favorite
        say "$_ is my favorite number";
        continue;
    }
    my @empty;
    when( @divisors ~~ @empty ) {
        say "Number is prime"
    }
    default {
        say "$_ is divisible by @divisors"
    }
}

sub divisors {
    my $number = shift;
    my @divisors = ();
    foreach my $divisor ( 2 .. ($number/2 + 1) ) {
        push @divisors, $divisor unless $number % $divisor;
    }
    return @divisors;
}

33、编写一个程序,将当前工作目录更改为某个特定的(硬编码)目录,例如系统的根目录,然后执行
ls -l
命令以获取该目录的长格式目录列表。(如果你使用的是非 Unix 系统,请使用你自己系统的命令来获取详细的目录列表。)

以下是实现该功能的代码:


chdir '/' or die "Can't chdir to root directory: $!";
exec 'ls', '-l' or die "Can't exec ls: $!";

第一行将当前工作目录更改为根目录,第二行使用多参数
exec
函数执行
ls -l
命令并将结果发送到标准输出。

34、修改之前的程序,将命令的输出发送到当前目录下名为 ls.out 的文件中。错误输出应发送到名为 ls.err 的文件中。(你无需特别处理这两个文件可能为空的情况)

可使用如下命令实现:


$ ls 1>ls.out 2>ls.err

该命令将标准输出重定向到
ls.out
文件,将标准错误输出重定向到
ls.err
文件。

35、编写一个程序,解析
date
命令的输出以确定当前是星期几。如果是工作日,则输出
get to work
;否则,输出
go play

date
命令的输出在周一以
Mon
开头。如果你使用的非Unix系统没有
date
命令,可以编写一个简单的伪程序,使其输出类似
date
命令的字符串。也可以使用以下两行代码:#!/usr/bin/perl print localtime( ). “
”;

以下是一个满足需求的Perl程序示例:


#!/usr/bin/perl
use strict;
use warnings;

# 获取date命令的输出
my $date_output = `date`;

# 提取星期几
if ($date_output =~ /^(Mon|Tue|Wed|Thu|Fri)/) {
    print "get to work
";
} else {
    print "go play
";
}

如果你的系统没有
date
命令,可以使用提供的两行代码替换获取
date
输出的部分:


#!/usr/bin/perl
use strict;
use warnings;

# 获取类似date命令输出的字符串
my $date_output = localtime() . "
";

# 提取星期几
if ($date_output =~ /^(Mon|Tue|Wed|Thu|Fri)/) {
    print "get to work
";
} else {
    print "go play
";
}

36、编写一个仅适用于Unix系统的无限循环程序,该程序能捕获信号,并报告捕获到了哪个信号以及之前看到该信号的次数。如果捕获到INT信号则退出程序。若可以使用命令行的kill命令,可通过 $ kill -USR1 12345 发送信号;若不能使用命令行的kill命令,可编写另一个程序向它发送信号,也可使用Perl单行命令:$ perl -e ‘kill HUP => 12345’。

以下是符合要求的程序代码:


use 5.010;

sub my_hup_handler {
    state $n;
    say 'Caught HUP: ', ++$n
}

sub my_usr1_handler {
    state $n;
    say 'Caught USR1: ', ++$n
}

sub my_usr2_handler {
    state $n;
    say 'Caught USR2: ', ++$n
}

sub my_int_handler {
    say 'Caught INT. Exiting.';
    exit
}

say "I am $$";

foreach my $signal ( qw(int hup usr1 usr2) ) {
    $SIG{ uc $signal } = "my_${signal}_handler";
}

while(1) {
    sleep 1
};

要向该程序发送信号,可在另一个终端会话中运行以下命令:


$ kill -HUP <进程ID>
$ perl -e 'kill HUP => <进程ID>
$ perl -e 'kill USR2 => <进程ID>'

运行该程序后,输出会显示捕获到的信号及其计数,捕获到INT信号时程序将退出。

37、修改练习的答案,使用YYYY – MM – DD格式报告时间。使用带有localtime和切片的map将纪元时间转换为所需的日期字符串。注意localtime文档中关于它返回的年份和月份值的说明。你的报告应如下所示:fred.txt 2011 – 10 – 15 2011 – 09 – 28 barney.txt 2011 – 10 – 13 2011 – 08 – 11 betty.txt 2011 – 10 – 15 2010 – 07 – 24


foreach my $file ( glob( '*' ) ) {
    my( $atime, $mtime ) = map {
        my( $year, $month, $day ) = (localtime($_))[5,4,3];
        $year += 1900;
        $month += 1;
        sprintf '%4d-%02d-%02d', $year, $month, $day;
    } (stat $file)[8,9];
    printf "%-20s %10s %10s
", $file, $atime, $mtime;
}

38、使用Perl语言输出“Hello, world!”,可以有哪些实现方式?

有以下几种实现方式:

使用
print
函数:

perl print "Hello, world!
";

若使用 Perl 5.10 或更高版本,可使用
say
函数:

perl use 5.010; say "Hello, world!";

从命令行运行,使用
-e
开关:

bash $ perl -e 'print "Hello, World
"'

从命令行运行,使用
-l
开关自动添加换行符:

bash $ perl -le 'print "Hello, World"'

39、编写一个Perl程序,从用户输入获取圆的半径,计算并输出该圆的周长

以下是实现该功能的 Perl 程序:


#!/usr/bin/perl
use strict;
use warnings;

print "请输入圆的半径: ";
chomp(my $radius = <STDIN>);

my $circumference = 2 * 3.14159 * $radius;
print "该圆的周长是: $circumference
";

将上述代码保存为一个
.pl
文件,例如
circle_perimeter.pl
,然后在终端中运行
perl circle_perimeter.pl
,按照提示输入圆的半径,程序将计算并输出圆的周长。

40、编写一个Perl程序,计算半径为12.5的圆的周长,并输出结果


#!/usr/bin/perl
use 5.010;
my $radius = 12.5;
my $circumference = 2 * 3.14159 * $radius;
say "半径为12.5的圆的周长是: $circumference";

41、编写一个Perl程序,提示用户输入圆的半径,然后计算并输出该圆的周长

以下是一个满足需求的Perl程序:


#!/usr/bin/perl
use strict;
use warnings;

print "请输入圆的半径: ";
my $radius = <STDIN>;
chomp($radius);

my $circumference = 2 * 3.14159 * $radius;
print "该圆的周长是: $circumference
";

该程序首先提示用户输入圆的半径,接着读取用户输入并去除换行符,然后使用公式
2 * π * 半径
计算圆的周长,最后输出计算结果。

42、编写一个Perl程序,提示用户输入圆的半径,检查半径是否为负数,如果是则将周长设为0,最后输出圆的周长

以下是实现该功能的Perl程序:


#!/usr/bin/perl
use strict;
use warnings;

print "请输入圆的半径: ";
my $radius = <STDIN>;
chomp($radius);

if ($radius < 0) {
    $radius = 0;
}

my $circumference = 2 * 3.14159 * $radius;
print "圆的周长是: $circumference
";

该程序首先提示用户输入圆的半径,然后检查输入的半径是否为负数,如果是则将半径设为0,最后计算并输出圆的周长。

43、编写一个Perl程序,提示用户输入两个数字,计算它们的乘积并输出结果

以下是实现该功能的Perl程序代码:


print "请输入第一个数字: ";
chomp(my $num1 = <STDIN>);
print "请输入第二个数字: ";
chomp(my $num2 = <STDIN>);
my $product = $num1 * $num2;
print "这两个数字的乘积是: $product
";

将上述代码保存为一个
.pl
文件,例如
multiply.pl
,然后在终端中运行
perl multiply.pl
即可。程序会依次提示你输入两个数字,输入完成后会计算并输出它们的乘积。

44、编写一个Perl程序,提示用户输入一个字符串和一个数字,将字符串重复指定的次数并输出结果

以下是实现该功能的Perl程序:


#!/usr/bin/perl
use strict;
use warnings;

print "请输入一个字符串: ";
chomp(my $string = <STDIN>);

print "请输入一个数字: ";
chomp(my $number = <STDIN>);

my $result = $string x $number;

print "重复后的结果是: $result
";

将上述代码保存为一个
.pl
文件,例如
repeat_string.pl
,然后在命令行中运行
perl repeat_string.pl
,按照提示输入字符串和数字,程序会将字符串重复指定的次数并输出结果。

45、编写一个Perl程序,提示用户输入多行文本,然后将这些行反转并输出

以下是一个满足需求的Perl程序示例:


#!/usr/bin/perl
use warnings;
use strict;

print "请输入多行文本,输入空行结束输入:
";

my @lines;
while (<STDIN>) {
    chomp;
    last if $_ eq '';
    push @lines, $_;
}

@lines = reverse @lines;

foreach my $line (@lines) {
    print $line, "
";
}

将上述代码保存为一个
.pl
文件,如
reverse_lines.pl
,然后在终端中运行
perl reverse_lines.pl
,按照提示输入多行文本,输入空行结束输入,程序会将输入的行反转后输出。

46、有一个数组 @names = qw/ fred betty barney dino wilma pebbles bamm – bamm /,编写程序让用户输入 1 到 7 的数字,每行一个,按 Ctrl – D 结束输入,然后根据用户输入的数字输出对应的数组元素

以下是实现该功能的 Perl 代码:


@names = qw/ fred betty barney dino wilma pebbles bamm - bamm /;
while (<>) { 
    chomp;
    if ($_ >= 1 && $_ <= 7) {
        print $names[$_ - 1], "
";
    } else {
        print "输入的数字不在 1 到 7 的范围内,请重新输入。
";
    }
}

这段代码首先定义了数组
@names
,然后使用
while (<>)
循环读取用户输入,每次读取一行并去除换行符。接着检查输入的数字是否在 1 到 7 的范围内,如果是,则输出数组中对应的元素;如果不是,则提示用户重新输入。按 Ctrl – D 结束输入。

47、编写程序,让用户输入一些行,按 Ctrl – D 结束输入,将输入的行排序后输出,要求实现输出在一行和输出在多行两种情况

以下是实现该功能的 Perl 代码:


#!/usr/bin/perl
use strict;
use warnings;

# 读取用户输入,直到按下 Ctrl-D
my @lines;
while (my $line = <STDIN>) {
    chomp $line;
    push @lines, $line;
}

# 对输入的行进行排序
my @sorted_lines = sort @lines;

# 输出在多行
print "多行输出:
";
foreach my $line (@sorted_lines) {
    print $line, "
";
}

# 输出在一行
print "一行输出:";
print join(" ", @sorted_lines), "
";

上述代码首先读取用户输入的行,存储在数组中。接着对数组进行排序,然后分别以多行和一行的形式输出排序后的行。

48、编写一个子例程 total,用于计算传入参数的总和

以下是编写
total
子例程的代码:


sub total {
    my $sum = 0;
    foreach my $num (@_) {
        $sum += $num;
    }
    return $sum;
}

这个子例程接收一个数字列表作为参数,通过遍历列表中的每个数字并将其累加到
$sum
变量中,最后返回总和。

49、编写程序,让用户输入一个字符串和一个数字,将字符串重复该数字次数后输出,要求字符串出现在不同行

以下是使用 Python 实现的代码:


string = input("请输入一个字符串:")
number = int(input("请输入一个数字:"))
for i in range(number):
    print(string)

上述代码首先通过
input
函数获取用户输入的字符串和数字,将数字转换为整数类型。然后使用
for
循环,循环次数为用户输入的数字,在每次循环中打印字符串,从而实现字符串重复指定次数并分行输出。

© 版权声明

相关文章

暂无评论

none
暂无评论...