Perl与Python文件操作及链接创建示例

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;
}

100、编写一个程序,提示用户输入一个目录名(默认为用户主目录),使用目录句柄列出该目录下的所有文件。

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


use strict;
use warnings;
use File::HomeDir;

# 提示用户输入目录名,默认为用户主目录
print "请输入一个目录名(留空则使用用户主目录):";
my $dirname = <STDIN>;
chomp $dirname;
$dirname = File::HomeDir->my_home unless $dirname;

# 打开目录
opendir my $dh, $dirname or die "无法打开目录 $dirname: $!";

# 读取并列出目录下的所有文件
while (my $name = readdir $dh) {
  next if $name =~ /^./; # 跳过隐藏文件
  print $name, "
";
}

# 关闭目录
closedir $dh;

这个程序首先提示用户输入目录名,如果用户没有输入,则使用用户主目录。然后打开该目录,读取并列出所有非隐藏文件,最后关闭目录。

101、编写一个程序,删除命令行参数指定的所有文件,并在删除失败时给出警告。

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


foreach my $file (@ARGV) {
    if (!unlink($file)) {
        warn "无法删除文件 $file: $!
";
    }
}

上述程序会遍历命令行参数中的所有文件,尝试删除它们。若删除失败,会给出相应的警告信息。

102、编写一个程序,为命令行参数指定的源文件创建一个硬链接到目标文件,如果目标文件是一个目录,则将源文件的硬链接创建到该目录下。

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


#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;

# 获取命令行参数
my ($source, $target) = @ARGV;

# 检查参数是否足够
if (!defined $source || !defined $target) {
    die "Usage: $0 <source_file> <target_file_or_directory>
";
}

# 检查源文件是否存在
if (! -e $source) {
    die "Source file $source does not exist.
";
}

# 检查目标是否为目录
if (-d $target) {
    # 如果是目录,构建目标文件路径
    my $filename = (File::Spec->splitpath($source))[2];
    $target = File::Spec->catfile($target, $filename);
}

# 创建硬链接
if (link($source, $target)) {
    print "Hard link created successfully from $source to $target.
";
} else {
    die "Failed to create hard link: $!
";
}

将上述代码保存为一个

.pl

文件,例如

create_hard_link.pl

,然后在命令行中运行,如:


perl create_hard_link.pl source_file.txt target_directory

或者


perl create_hard_link.pl source_file.txt target_file.txt

103、编写一个程序,根据命令行参数的 -s 选项,为命令行参数指定的源文件创建一个符号链接或硬链接到目标文件,如果目标文件是一个目录,则将源文件的链接创建到该目录下。

以下是一个使用 Python 实现该功能的示例代码:


import os
import sys

is_symbolic = False
if '-s' in sys.argv:
    is_symbolic = True
    sys.argv.remove('-s')

if len(sys.argv) != 3:
    print('用法: python script.py [-s] 源文件 目标文件')
    sys.exit(1)

source_file = sys.argv[1]
target = sys.argv[2]

if os.path.isdir(target):
    target = os.path.join(target, os.path.basename(source_file))

if is_symbolic:
    try:
        os.symlink(source_file, target)
        print(f'符号链接创建成功: {target}')
    except FileExistsError:
        print(f'目标文件 {target} 已存在')
    except PermissionError:
        print(f'没有足够权限创建符号链接到 {target}')
    except Exception as e:
        print(f'创建符号链接时出错: {e}')
else:
    try:
        os.link(source_file, target)
        print(f'硬链接创建成功: {target}')
    except FileExistsError:
        print(f'目标文件 {target} 已存在')
    except PermissionError:
        print(f'没有足够权限创建硬链接到 {target}')
    except Exception as e:
        print(f'创建硬链接时出错: {e}')

代码说明:


解析命令行参数

:检查

-s

选项是否存在,如果存在则将

is_symbolic

标志设置为

True

,并从参数列表中移除

-s


检查参数数量

:确保命令行参数包含源文件和目标文件。


处理目标目录

:如果目标是一个目录,则将源文件的名称添加到目标路径中。


创建链接

:根据

is_symbolic

标志创建符号链接或硬链接,并处理可能的异常。

104、编写一个程序,从标准输入读取一系列数字,将它们排序后以右对齐的格式输出。代码中使用了

push @numbers, split while <>;

这一行,解释其作用,并说明如果使用

%20s

代替

%20g

进行输出会有什么不同。

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


my @numbers;
push @numbers, split while <>;
foreach (sort { $a <=> $b } @numbers) {
    printf "%20g
", $_;
}

push @numbers, split while <>;

的作用是逐行读取标准输入,默认按空白字符分割每行内容为多个元素,再将这些元素添加到

@numbers

数组中。

如果使用

%20s

代替

%20g

进行输出:

%20s

是字符串格式,输出时字符串不会被改变,如

1.50


1.5


04


4

这些输入中的额外零字符会保留;


%20g

是数字格式,相等的数字在输出时会显示一致。

105、在对数字进行排序和打印的代码中,如果使用 %20s 而不是 %20g,会有什么不同?

下面是给定的【文本内容】:

%20s

是字符串格式,输出时字符串不会改变,像

1.50


04

中的额外零字符仍会保留;

%20g

是数字格式,相等的数字输出会相同。

106、如何先按姓氏、再按名字对哈希表 %last_name 的键进行排序并输出?

可以使用以下代码实现:


my @keys = sort {
    "L$last_name{$a}" cmp "L$last_name{$b}" # by last name
    or "L$a" cmp "L$b" # by first name
} keys %last_name;

foreach (@keys) {
    print "$last_name{$_}, $_
";
}

107、如何使用

given

重写猜数字程序?

以下是使用

given

重写猜数字程序的示例代码:


use 5.010;
my $Verbose = $ENV{VERBOSE} // 1;
my $secret = int(1 + rand 100);
print "Don't tell anyone, but the secret number is $secret.
" if $Verbose;
LOOP: {
    print "Please enter a guess from 1 to 100: ";
    chomp(my $guess = <STDIN>);
    my $found_it = 0;
    given( $guess ) {
        when( ! /Ad+/ ) { say "Not a number!" }
        when( $_ > $secret ) { say "Too High!" }
        when( $_ < $secret ) { say "Too low!" }
        default { say "Just right!";$found_it++ }
    }
    last LOOP if $found_it;
    redo LOOP;
}

108、使用

given

重写数字猜谜程序(不一定使用智能匹配),该程序要求用户猜一个1到100之间的随机整数,根据用户输入给出相应提示,直到猜对为止。

以下是重写后的代码:


use 5.010;
my $Verbose = $ENV{VERBOSE} // 1;
my $secret = int(1 + rand 100);
print "Don't tell anyone, but the secret number is $secret.
" if $Verbose;
LOOP: {
    print "Please enter a guess from 1 to 100: ";
    chomp(my $guess = <STDIN>);
    my $found_it = 0;
    given( $guess ) {
        when( ! /Ad+/ ) { say "Not a number!" }
        when( $_ > $secret ) { say "Too High!" }
        when( $_ < $secret ) { say "Too low!" }
        default { say "Just right!";$found_it++ }
    }
    last LOOP if $found_it;
    redo LOOP;
}

109、编写一个程序,使用

given

语句打印从 1 到 105 的数字,若数字能被 3 整除则在其后追加 ‘Fizz’,能被 5 整除则追加 ‘Buzz’,能被 7 整除则追加 ‘Sausage’。

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


use feature 'given';
no warnings 'experimental::smartmatch';
for (1..105) {
    given ($_) {
        my $output = $_;
        if ($_ % 3 == 0) {
            $output .= ' Fizz';
        }
        if ($_ % 5 == 0) {
            $output .= ' Buzz';
        }
        if ($_ % 7 == 0) {
            $output .= ' Sausage';
        }
        print $output . "
";
    }
}

这段代码使用

for

循环遍历 1 到 105 的数字,在

given

语句块中,根据数字能否被 3、5、7 整除来追加相应的字符串,并将结果打印输出。

110、编写一个程序,在 for 块中直接使用 when 来检查作为命令行参数传递的文件的存在性、可读性、可写性和可执行性。

以下是满足需求的 Perl 代码:


use 5.010;
for( @ARGV ) {
    say "Processing $_";
    when( ! -e ) { say "File does not exist!" }
    when( -r _ ) { say "Readable!"; continue }
    when( -w _ ) { say "Writable!"; continue }
    when( -x _ ) { say "Executable!"; continue }
}

此程序会遍历命令行传入的所有文件,检查每个文件的存在性、可读性、可写性和可执行性,并输出相应结果。

111、编写一个使用

given

和智能匹配的程序,检查作为命令行参数传递的数字是否为质数。如果不是,则报告其除数。

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


use 5.010;
# 定义一个子例程来返回一个数的除数列表
sub divisors {
    my $number = shift;
    my @divisors = ();
    foreach my $divisor ( 2 .. ( $number/2 ) ) {
        push @divisors, $divisor unless $number % $divisor;
    }
    return @divisors;
}
# 检查命令行参数
if (@ARGV != 1) {
    die "请提供一个数字作为命令行参数。
";
}
# 获取命令行参数
my $number = $ARGV[0];
# 检查输入是否为数字
if ($number !~ /Ad+/) {
    say "输入不是一个有效的数字!";
    exit;
}
given ($number) {
    my @divisors = divisors($number);
    when (@divisors ~~ []) {
        say "$number 是质数。";
    }
    default {
        say "$number 的除数(除 1 和它本身)是:@divisors";
    }
}

代码解释:


divisors

子例程

:该子例程接受一个数字作为参数,并返回该数字的所有除数(除 1 和该数字本身)的列表。


输入检查

:程序首先检查是否提供了一个命令行参数,如果没有则终止程序。然后检查输入是否为有效的数字,如果不是则输出错误信息并退出。


given

语句

:使用

given

语句对输入的数字进行处理。调用

divisors

子例程获取除数列表。如果除数列表为空,则表示该数字是质数,输出相应信息。否则,输出该数字的除数列表。

112、编写一个程序,报告一个数是偶数、奇数、能被一个喜欢的数字(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";
    }
    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 .. ($ARGV[0]/2 + 1) ) {
        push @divisors, $divisor unless $number % $divisor;
    }
    return @divisors;
}

该程序通过

given - when

结构和智能匹配操作符

~~

来判断并报告数字的相关属性。

113、编写一个程序,将当前工作目录更改为根目录并执行 ‘ls -l’ 命令。

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


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

第一行将当前工作目录更改为根目录,第二行使用多参数

exec

函数执行

'ls -l'

命令并将结果发送到标准输出。

114、编写一个程序,将标准输出(STDOUT)和标准错误输出(STDERR)分别重定向到文件 ‘ls.out’ 和 ‘ls.err’,将当前工作目录更改为根目录,并执行 ‘ls -l’ 命令。

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


open STDOUT, '>', 'ls.out' or die "Can't write to ls.out: $!";
open STDERR, '>', 'ls.err' or die "Can't write to ls.err: $!";
chdir '/' or die "Can't chdir to root directory: $!";
exec 'ls', '-l' or die "Can't exec ls: $!";

代码解释:

前两行将

STDOUT


STDERR

分别重定向到

'ls.out'


'ls.err'

文件。

第三行将当前工作目录更改为根目录。

最后一行执行

'ls -l'

命令。如果命令执行失败,会输出错误信息。

115、编写代码实现将当前工作目录更改为根目录并执行 ‘ls -l’ 命令

在Python中可以使用以下代码实现:


import os
# 更改当前工作目录为根目录
os.chdir('/')
# 执行 'ls -l' 命令
os.system('ls -l')

在Bash脚本中可以这样写:


#!/bin/bash
# 更改当前工作目录为根目录
cd /
# 执行 'ls -l' 命令
ls -l

116、编写代码实现将标准输出和标准错误输出重定向到文件,然后将当前工作目录更改为根目录并执行 ‘ls -l’ 命令,并思考相关错误信息的输出位置

以下是一个示例的Python代码来实现该功能:


import os

# 重定向标准输出和标准错误输出到文件
with open('ls.out', 'w') as stdout_file, open('ls.err', 'w') as stderr_file:
    try:
        # 更改当前工作目录到根目录
        os.chdir('/')
        # 执行 ls -l 命令
        result = os.popen('ls -l 2>&1').read()
        # 将标准输出写入文件
        stdout_file.write(result)
    except Exception as e:
        # 将错误信息写入错误文件
        stderr_file.write(str(e))

在上述代码中,使用

os.popen('ls -l 2>&1').read()

把标准错误输出重定向到标准输出,然后将所有输出写入

ls.out

文件。如果在更改目录或执行命令时发生异常,异常信息会被捕获并写入

ls.err

文件。

117、编写代码设置信号处理程序来捕获一些信号,并在另一个终端会话中发送信号进行测试

以下是一个示例,展示如何使用Python设置信号处理程序来捕获信号,并在另一个终端会话中发送信号进行测试。

编写代码设置信号处理程序(Python示例)


import signal
import time

# 定义信号处理函数
# 当接收到SIGINT(Ctrl + C)或SIGTERM信号时,会调用这个函数
# 它会打印一条消息并退出程序
def signal_handler(signum, frame):
    print(f'接收到信号 {signum},程序即将退出。')
    exit(0)

# 注册信号处理程序
# 将SIGINT(通常是Ctrl + C触发)和SIGTERM信号与信号处理函数绑定
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

print('程序正在运行,按Ctrl + C或发送SIGTERM信号来测试。')
while True:
    time.sleep(1)

测试步骤


运行程序

:将上述代码保存为一个Python文件,例如

signal_test.py

,然后在终端中运行:

python signal_test.py

程序会开始运行并等待信号。


发送信号

:在另一个终端会话中,使用

ps

命令找到正在运行的Python程序的进程ID(PID)。例如:

ps -ef | grep signal_test.py

然后使用

kill

命令发送信号。

发送SIGTERM信号(这是正常的终止信号):

kill <PID>

这里的

<PID>

是你找到的Python程序的进程ID。

如果你想发送SIGINT信号,可以在运行程序的终端中按

Ctrl + C

注意事项

不同的操作系统和编程语言可能有不同的信号处理方式和信号编号。上述示例是基于Python和Unix/Linux系统的。

某些信号(如SIGKILL)是不能被捕获和处理的,因为它们是用来强制终止进程的。

© 版权声明

相关文章

暂无评论

none
暂无评论...