能否优化这款用于查找系统所有Perl安装的命令行Perl脚本?
Perl脚本优化:修复Cygwin显示异常并增强稳定性
问题背景
原脚本用于扫描系统$PATH环境变量中的所有Perl安装实例,输出包含Perl版本、文件大小、安装路径及MD5校验和等信息,但在Cygwin系统上存在显示异常问题,以下是修复并优化后的版本。
优化后的脚本
#!/usr/bin/env perl # Last modified: Sat Aug 24 2024 10:48:44 PM -04:00 [EDT] # 优化版本:修复Cygwin兼容性,增强错误处理与格式化稳定性 use strict; use warnings; use File::Which; use File::Basename; use File::stat; use Digest::MD5; =head1 安装 `chmod 700 perlwitch` - 在GNU/Linux及类Unix系统执行 =head1 使用 `perl perlwitch` =cut # 获取所有Perl可执行文件 my @heap = which('perl'); # 过滤非Windows/Cygwin下的.exe文件(仅针对Windows/Cygwin环境) if ($^O =~ /^(cygwin|MSWin32)$/) { @heap = grep { /\.exe$/i } @heap; } my @versions; my $max_path_len = 0; # 预处理:获取每个Perl的版本并计算最长路径长度 foreach my $perl_path (@heap) { $max_path_len = length($perl_path) if length($perl_path) > $max_path_len; # 安全打开管道获取版本信息,修正优先级问题 open my $read_pipe, '-|', $perl_path, '-v' or do { warn "无法执行 $perl_path 获取版本信息: $!\n"; push @versions, '未知版本'; next; }; my $version = '未知版本'; while (<$read_pipe>) { # 修正正则表达式,准确匹配Perl版本格式(如v5.36.3) if (/This is perl .+(v\d+\.\d+\.\d+)\)/) { $version = $1; last; # 匹配到后立即退出循环,提升效率 } } close $read_pipe or warn "关闭管道时出错: $?\n"; push @versions, $version; } # 计算格式化参数,避免负数长度 my $path_fmt_len = $max_path_len + 6; my $dir_fmt_len = $max_path_len > 4 ? $max_path_len - 4 : 10; # 最小保留10位宽度 # 输出表头 printf "%-${path_fmt_len}s %-10s %10s %-${dir_fmt_len}s %s\n", 'Perl路径', '版本', '文件大小', '安装目录', 'MD5校验和'; print '-' x ($path_fmt_len + 10 + 12 + $dir_fmt_len + 33), "\n"; # 遍历输出每个Perl实例信息 for my $index (0..$#heap) { my $perl_path = $heap[$index]; my $version = $versions[$index]; # 获取文件大小 my $st = stat($perl_path); my $file_size = $st ? $st->size : '无法获取'; # 获取安装目录 my (undef, $install_dir, undef) = fileparse($perl_path); # 计算MD5校验和 my $md5_sum = csum($perl_path); # 格式化输出,确保对齐 printf "%-${path_fmt_len}s %-10s %10s %-${dir_fmt_len}s %s\n", $perl_path, $version, $file_size, $install_dir, $md5_sum; } # MD5校验和计算子函数 sub csum { my $fpath = shift; open my $fh, '<', $fpath or do { warn "无法打开文件 $fpath: $!\n"; return '计算失败'; }; binmode $fh; my $checksum = Digest::MD5->new->addfile($fh)->hexdigest; close $fh; return $checksum; } __END__ =pod 本程序用于定位系统`$PATH`环境变量中所有可找到的Perl安装实例,适合在久未使用或不熟悉的系统上快速梳理Perl环境。 输出包含MD5校验和,可轻松识别重复实例(例如通过符号链接指向同一文件的情况,如Debian系统中/bin链接到/usr/bin)。 =head3 复杂场景示例输出(Cygwin与Windows Perl共存) Perl路径 版本 文件大小 安装目录 MD5校验和 ------------------------------------------------------------------------------------------- C:\ix\cygwin\bin\perl.EXE v5.36.3 12819 C:\ix\cygwin\bin\ 68ba8b0c3d9bb4859076e938e0cbdafe C:\perl\perl\bin\perl.EXE v5.32.1 39936 C:\perl\perl\bin\ 3686d8a7e98b82a6452f88fef293ca1a =head2 许可证 Copyright (c) 2024 Soren Andersen. All rights reserved. 本库为自由软件;可依据与Perl相同的条款重新发布和修改。 =cut
核心优化点
- 修复Cygwin兼容性:
- 替换原脚本中易出错的
splice过滤逻辑,改用grep安全过滤.exe文件,避免索引混乱 - 确保路径解析与文件状态获取在Cygwin混合路径环境下正常工作
- 替换原脚本中易出错的
- 增强版本匹配准确性:修正正则表达式,准确匹配
vX.X.X格式的Perl版本,避免匹配失败 - 优化错误处理:
- 修正管道打开的优先级问题(用
or替代||),确保错误提示准确触发 - 对文件打开、版本获取等环节添加容错处理,避免脚本中途崩溃
- 修正管道打开的优先级问题(用
- 稳定格式化输出:
- 处理路径长度过短的情况,避免
$strl-4产生负数导致格式化报错 - 添加表头与分隔线,提升输出可读性
- 处理路径长度过短的情况,避免
- 代码规范:开启
strict模式,所有变量添加my声明,提升代码可维护性
内容的提问来源于stack exchange,提问作者amphibole
相关产品推荐
相关产品推荐

