系统管理员的 Perl 技巧

10 位读者喜欢这个。
Perl tricks for system administrators

Opensource.com

您是否知道 Perl 是一种非常适合系统管理员的编程语言?Perl 是平台独立的,因此您可以在不同的操作系统上执行操作,而无需重写脚本。Perl 脚本编写快速而简单,其可移植性使您的脚本非常有用。这里有一些示例,仅供激发您的创意!

重命名一批文件

假设您需要重命名目录中的一大堆文件。在本例中,我们有一个目录,其中包含大量 .xml 文件,我们想将它们全部重命名为 .html。非常简单!

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

foreach my $file (glob "*.xml") {
    my $new = substr($file, 0, -3) . "html";
    rename $file, $new;
}

然后只需 cd 到您需要进行更改的目录,并运行脚本。如果需要定期运行它,您可以将其放在 cron 作业中,并且可以轻松增强它以接受参数。

说到接受参数,让我们看看一个执行此操作的脚本。

创建 Linux 用户帐户

假设您需要定期在系统上创建 Linux 用户帐户,并且用户名的格式是名字首字母/姓氏,这在许多企业中很常见。(当然,这是一个好主意,直到您遇到 John Smith 和 Jane Smith 在同一家公司工作,或者希望 John 拥有两个帐户,因为他在两个不同的部门兼职。但请理解我的幽默,好吗?)每个用户帐户都需要位于基于其部门的组中,并且主目录的格式为 /home/<department>/<username>。让我们看一下执行此操作的脚本

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

my $adduser = '/usr/sbin/adduser';

use Getopt::Long qw(GetOptions);

# If the user calls the script with no parameters, 
# give them help!

if (not @ARGV) {
    usage();
}

# Gather our options; if they specify any undefined option, 
# they'll get sent some help!

my %opts;
GetOptions(\%opts,
    'fname=s',
    'lname=s',
    'dept=s',
    'run',
) or usage();

# Let's validate our inputs. All three parameters are 
# required, and must be alphabetic.
# You could be clever, and do this with a foreach loop, 
# but let's keep it simple for now.

if (not $opts{fname} or $opts{fname} !~ /^[a-zA-Z]+$/) {
    usage("First name must be alphabetic");
}
if (not $opts{lname} or $opts{lname} !~ /^[a-zA-Z]+$/) {
    usage("Last name must be alphabetic");
}
if (not $opts{dept} or $opts{dept} !~ /^[a-zA-Z]+$/) {
    usage("Department must be alphabetic");
}

# Construct the username and home directory

my $username = lc( substr($opts{fname}, 0, 1) . $opts{lname});
my $home     = "/home/$opts{dept}/$username";

# Show them what we've got ready to go.

print "Name:           $opts{fname} $opts{lname}\n";
print "Username:       $username\n";
print "Department:     $opts{dept}\n";
print "Home directory: $home\n\n";

# use qq() here, so that the quotes in the --gecos flag
# get carried into the command!

my $cmd = qq($adduser --home $home --ingroup $opts{dept} \\
--gecos "$opts{fname} $opts{lname}" $username);

print "$cmd\n";
if ($opts{run}) {
    system $cmd;
} else {
    print "You need to add the --run flag to actually execute\n";
}

sub usage {
    my ($msg) = @_;
    if ($msg) {
        print "$msg\n\n";
    }
    print "Usage: $0 --fname FirstName --lname LastName --dept Department --run\n";
    exit;
}

与之前的脚本一样,有很多增强的机会,但像这样的脚本可能就是您完成此任务所需的全部。

再来一个,只是为了好玩!

更改目录树中每个 Perl 源文件中的版权文本

现在我们将尝试批量编辑。假设您有一个包含大量代码的目录,并且每个文件中的某个位置都有版权声明。(Rich Bowen 写了一篇很棒的文章, 版权声明在开源代码中激增,几年前讨论了开源代码中版权声明的智慧。这是一篇值得一读的文章,我强烈推荐。但再说一次,请理解我的幽默。)您想要更改目录树中每个文件中的文本。File::FindFile::Slurp 是您的朋友!

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

use File::Find qw(find);
use File::Slurp qw(read_file write_file);

# If the user gives a directory name, use that. Otherwise, 
# use the current directory.

my $dir = $ARGV[0] || '.';

# File::Find::find is kind of dark-arts magic. 
# You give it a reference to some code, 
# and a directory to hunt in, and it will 
# execute that code  on every file in the 
# directory, and all subdirectories. In this 
# case, \&change_file is the reference 
# to our code, a subroutine.  You could, if 
# what you wanted to do was really short, 
# include it in a { } block instead. But doing 
# it this way is nice and readable.

find( \&change_file, $dir);
 
sub change_file {
    my $name= $_;

    # If the file is a directory, symlink, or other 
    # non-regular file, don't do anything

    if (not -f $name) {
        return;
    }
    # If it's not Perl, don't do anything.

    if (substr($name, -3) ne ".pl") {
        return;
    }
    print "$name\n";

    # Gobble up the file, complete with carriage
    # returns and everything. 
    # Be wary of this if you have very large files
    # on a system with limited memory!

    my $data = read_file($name);

    # Use a regex to make the change. If the string appears 
    # more than once, this will change it everywhere!

    $data =~ s/Copyright Old/Copyright New/g;

    # Let's not ruin our original files

    my $backup = "$name.bak";
    rename $name, $backup; 
    write_file($name, $data);

    return;
}

由于 Perl 的可移植性,您可以在 Windows 系统以及 Linux 系统上使用此脚本——由于底层的 Perl 解释器代码,它可以正常工作。在我们上面的创建帐户代码中,该代码是不可移植的,但它是 Linux 特定的,因为它使用了 Linux 命令,例如 adduser

根据我的经验,我发现最好将这些东西的 Git 存储库放在某个地方,以便我可以克隆到我正在使用的每个新系统上。随着时间的推移,您会想到对代码进行更改以增强功能,或者您会添加新脚本,而 Git 可以帮助您确保所有工具和技巧都可以在您的所有系统上使用。

我希望这些小脚本为您提供了一些关于如何使用 Perl 使您的系统管理生活更轻松的想法。除了这些较长的脚本外,还可以查看 Mischa Peterson 汇编的 Perl 单行代码和指向其他 Perl 魔法的链接 的精彩列表。

User profile image.
Ruth Holloway 长期以来一直是系统管理员和软件开发人员,早在 VAX 11/780 上就开始了她的职业生涯。她的职业生涯(到目前为止)大部分时间都在为图书馆提供技术需求服务,并且自 2008 年以来一直是 Koha 开源图书馆自动化套件的贡献者。Ruth 目前是 Clearbuilt 的 Perl 开发人员和项目负责人。

9 条评论

关于 glob() 的警告。默认版本基于 C-shell,并在空格处中断。如果您的文件名中有空格,请使用 File::Glob 中的 BSD 版本。

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

use File::Glob qw( :bsd_glob );

foreach my $file (glob "*.xml") {
my $new = substr($file, 0, -3) . "html";
rename $file, $new;
}

注意:perl 并非始终安装在 /usr/bin 中(并且您可能并不总是想使用系统 perl),因此最好执行类似操作

#!/usr/bin/env perl
use 5.14.0;
use strict;
use warnings;
# 在此处插入代码

反驳:除非 perl 在 PATH 环境变量中,否则引用 env perl 的 shebang 将不起作用... 而在 cron 作业的默认环境中,情况并非如此。因此,如果您的 perl 应用程序可能从 cron 运行,请在使用花哨的 env shebang 之前仔细考虑。

回复 ,作者:Tim Van den La… (未验证)

呃……为什么不直接从命令行使用“rename 's/\.xml$/.html/' *.xml”?

TIMTOWTDI,当然,这是一个方法,虽然我在我身边的一台机器(CentOS 7,以 bash 作为我的 shell)上尝试过,但收到了一个错误……这正是重点。它可能适用于某些用户,在某些 shell 上,在某些时候。如果您有一组不同的系统,使用 Perl 作为某种抽象层可以让您不必担心确切的实现。将脚本复制到任何可以运行 Perl 的系统上,它就可以正常工作。

回复 ,作者:kasbah (未验证)

对于第一个示例,我非常建议使用 rename 命令,如下所示

$ rename 's/\.xml$/html/' *.bak

回复最后一个评论 *.xml 而不是 *.bak ;-) 剪切和粘贴错误,抱歉

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.