Regex Perl文件复制输出

Regex Perl文件复制输出,regex,perl,file-io,duplicates,Regex,Perl,File Io,Duplicates,我正在尝试编写一个菜单驱动的模块化perl脚本,它将捕获用户输入并自动化网络配置过程。此脚本必须能够安装所需的Arch软件包,配置AP模式,为用户选择的界面配置DHCP或静态地址,并提供启用桥接的选项。(编辑:脚本还需要能够启用和配置dhcpd服务) 我现在要做的是创建rc.conf文件的备份,读取文件并编辑需要修改的行(如果网络接口已经静态配置)。这个脚本是在ArchLinux中使用的,我进行了一些搜索,没有找到任何特别满足我需要的东西 使用通用输入 $ip=1.1.1.1$Bcast=2.2

我正在尝试编写一个菜单驱动的模块化perl脚本,它将捕获用户输入并自动化网络配置过程。此脚本必须能够安装所需的Arch软件包,配置AP模式,为用户选择的界面配置DHCP或静态地址,并提供启用桥接的选项。(编辑:脚本还需要能够启用和配置dhcpd服务)

我现在要做的是创建rc.conf文件的备份,读取文件并编辑需要修改的行(如果网络接口已经静态配置)。这个脚本是在ArchLinux中使用的,我进行了一些搜索,没有找到任何特别满足我需要的东西

使用通用输入
$ip=1.1.1.1$Bcast=2.2.2.2$网络掩码=3.3.3.3$GW=4.4.4.4

我花了大约两个小时阅读有关文件I/O的内容,并尝试了一些不起作用的方法,包括放弃多文件IO方法和使用类似的方法:
while(){s/^interface.?=(.*$/“interface=@if[0]\n”/;}
为每个需要替换的值提供输入,但无法使其实际执行任何操作

   if (system ("cat","/etc/rc.conf","|","grep","interface")){   
    use File::Copy "cp";
    $filename = "/etc/rc.conf"; 
    $tempfile = "/etc/rc.tmp";  
    $bak = "/etc/rc.bak";
    cp($filename,$bak);
    open(IS, $filename); 
    open(OS, ">$tempfile"); 
    while(<IS>){ 
        if($_ =~ /^interface.?=(.*)$/){ print OS"interface=@if[0] \n";}
        if($_ =~ /^address.?=(.*)$/){ print OS "address=$ip\n";}
        if($_ =~/^netmask.?=(.*)$/){ print OS "netmask=$netmask\n";}
        if($_ =~/^broadcast.?=(.*)$/){ print OS "broadcast=$Bcast\n";}
        if($_ =~/^gateway.?=(.*)$/){ print OS "gateway=$GW\n"; }
        else {print OS $_;} 
    }
    close(IS); close(OS); 
    unlink($filename); rename($tempfile, $filename);
}
rc.conf之后

#
# /etc/rc.conf - Main Configuration for Arch Linux

. /etc/archiso/functions

LOCALE_DEFAULT="en_US.UTF-8"
DAEMON_LOCALE_DEFAULT="no"
CLOCK_DEFAULT="UTC"
TIMEZONE_DEFAULT="Canada/Pacific"
KEYMAP_DEFAULT="us"
CONSOLEFONT_DEFAULT=
CONSOLEMAP_DEFAULT=
USECOLOR_DEFAULT="yes"

LOCALE="$(kernel_cmdline locale ${LOCALE_DEFAULT})"
DAEMON_LOCALE="$(kernel_cmdline daemon_locale ${DAEMON_LOCALE_DEFAULT})"
HARDWARECLOCK="$(kernel_cmdline clock ${CLOCK_DEFAULT})"
TIMEZONE="$(kernel_cmdline timezone ${TIMEZONE_DEFAULT})"
KEYMAP="$(kernel_cmdline keymap ${KEYMAP_DEFAULT})"
CONSOLEFONT="$(kernel_cmdline consolefont ${CONSOLEFONT_DEFAULT})"
CONSOLEMAP="$(kernel_cmdline consolemap ${CONSOLEMAP_DEFAULT})"
USECOLOR="$(kernel_cmdline usecolor ${USECOLOR_DEFAULT})"

MODULES=()

UDEV_TIMEOUT=30
USEDMRAID="no"
USEBTRFS="no"
USELVM="no"

HOSTNAME="archiso"

DAEMONS=(hwclock syslog-ng)

interface=eth0 
interface=eth0
address=1.1.1.1
address=192.168.0.99
netmask=3.3.3.3
netmask=255.255.255.0
broadcast=2.2.2.2
broadcast=192.168.0.255
gateway=4.4.4.4

问题是你的
if
/
if
/
if
/
if
/
if
/
else
链,它应该是一个
if
/
elsif
/
elsif
/
elsif
/
elsif
/
elsif
链。
else{print OS$\ucode}
会在与
gateway=
不匹配的每一行触发,包括与
接口
匹配的行、
地址
等。

我不打算评论脚本其余部分的智慧,但您有:

if (system ("cat","/etc/rc.conf","|","grep","interface")){ 
成功返回
0

因此,只有当
system
调用失败时,您才会进入块

如果事实上,我现在在Windows系统上,没有
/etc/rc.conf
(但是
cat
grep
),这要感谢。运行以下脚本:

#!/usr/bin/env perl

use strict; use warnings;

if (system ("cat","/etc/rc.conf","|","grep","interface")){
    print "*** it worked! ***\n";
    if ($? == -1) {
        print "failed to execute: $!\n";
    }
    elsif ($? & 127) {
        printf "child died with signal %d, %s coredump\n",
            ($? & 127),  ($? & 128) ? 'with' : 'without';
    }
    else {
        printf "child exited with value %d\n", $? >> 8;
    }
}
生成输出:

cat: /etc/rc.conf: No such file or directory cat: |: No such file or directory cat: grep: No such file or directory cat: interface: No such file or directory *** it worked! *** child exited with value 1 另一方面,我宁愿不信任传播退出状态的shell

以下内容将为您指明一个更好的方向:

#!/usr/bin/env perl

use strict;use warnings;

my %lookup = (
    eth0 => {
        address => '1.1.1.1',
        broadcast => '2.2.2.2',
        netmask => '3.3.3.3',
        gateway => '4.4.4.4',
    },
    wlan0 => {
        address => '5.5.5.5',
        broadcast => '6.6.6.6',
        netmask => '7.7.7.7',
        gateway => '8.8.8.8',
    },

);

while (my $line = <DATA>) {
    if (my ($interface) = ($line =~ /^interface=(\S+)/)) {
        print $line;
        if (exists $lookup{$interface}) {
            $line = process_interface(\*DATA, $lookup{$interface});
            redo;
        }
    }
    else {
        print $line;
    }
}

sub process_interface {
    my ($fh, $lookup) = @_;
    my $keys = join '|', sort keys %$lookup;

    while (my $line = <DATA>) {
        $line =~ s/\A($keys)=.+/$1=$lookup->{$1}/
            or return $line;
        print $line;
    }

    return;
}

__DATA__
#
# /etc/rc.conf - Main Configuration for Arch Linux

. /etc/archiso/functions

# stuff

interface=eth0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
interface=wlan0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
!/usr/bin/env perl
使用严格;使用警告;
我的%lookup=(
eth0=>{
地址=>'1.1.1.1',
广播=>“2.2.2.2”,
网络掩码=>“3.3.3.3”,
网关=>“4.4.4.4”,
},
wlan0=>{
地址=>'5.5.5.5',
广播=>“6.6.6.6”,
网络掩码=>“7.7.7.7”,
网关=>'8.8.8.8',
},
);
while(我的$line=){
如果(我的($interface)=($line=~/^interface=(\S+/)){
打印$行;
if(存在$lookup{$interface}){
$line=进程接口(\*数据,$lookup{$interface});
重做;
}
}
否则{
打印$行;
}
}
子进程接口{
我的($fh,$lookup)=@;
my$keys=join'|',sort keys%$lookup;
while(我的$line=){
$line=~s/\A($keys)=.+/$1=$lookup->{$1}/
或返回$line;
打印$行;
}
返回;
}
__资料__
#
#/etc/rc.conf-Arch Linux的主配置
/etc/archiso/functions
#东西
接口=eth0
地址=192.168.0.99
网络掩码=255.255.255.0
广播=192.168.0.255
网关=192.168.0.1
接口=wlan0
地址=192.168.0.99
网络掩码=255.255.255.0
广播=192.168.0.255
网关=192.168.0.1
输出:

# # /etc/rc.conf - Main Configuration for Arch Linux . /etc/archiso/functions # stuff interface=eth0 address=1.1.1.1 netmask=3.3.3.3 broadcast=2.2.2.2 gateway=4.4.4.4 interface=wlan0 address=5.5.5.5 netmask=7.7.7.7 broadcast=6.6.6.6 gateway=8.8.8.8 # #/etc/rc.conf-Arch Linux的主配置 /etc/archiso/functions #东西 接口=eth0 地址=1.1.1.1 网络掩码=3.3.3.3 广播=2.2.2.2 网关=4.4.4.4 接口=wlan0 地址=5.5.5.5 网络掩码=7.7.7.7 广播=6.6.6.6
gateway=8.8.8.8感谢您的回复,我稍后将进一步了解您的脚本的运行情况。我是perl新手,订购了几本书,但我现在在海外服务,这些书需要几个月才能到达这里。
if(system(“cat”)、“/etc/rc.conf”、“|”、“grep”、“interface”)){
行实际上按照我的预期工作。有没有更好的方法来查看rc.conf文件中是否已经为“interface”分配了值?@Gosu我对
系统的事情感到困惑。我现在在Windows系统上,所以我无法检查,但是如果调用成功,它不应该进入循环体,因为
系统
成功后肯定会返回
0
。您是否使用了一个不包含
interface
字样的文件进行了尝试?我会通过查找直到找到一个接口来将其合并到脚本中。我将更新我的示例。在我的系统上,
system()
调用
cat
,该实用程序尝试打开一个名为“/etc/rc.conf”的文件、一个名为“|”的文件、一个名为“grep”的文件和一个名为“interface”的文件。@pilcrow是的,我也识别了这一点,并立即将其合并到我的帖子中。您的
系统()
行引人注目:① 退货支票似乎颠倒为,② 系统的列表调用通常用于绕过shell,但您需要shell来设置管道,并且,不那么引人注目,③
cat(1)
是免费的,因为
grep(1)
很高兴地接受了一个文件参数。感谢您的回复,返回检查实际上正如我所希望的那样工作。您能详细说明为什么它会失败吗?有没有更优雅的方式让我运行此检查?我正在重写
grep(1)
line以包含文件并删除免费的
cat(1)
谢谢。只有当system()报告故障时,
if(system(…)
条件才为真,这似乎与您想要的相反。
#!/usr/bin/env perl

use strict;use warnings;

my %lookup = (
    eth0 => {
        address => '1.1.1.1',
        broadcast => '2.2.2.2',
        netmask => '3.3.3.3',
        gateway => '4.4.4.4',
    },
    wlan0 => {
        address => '5.5.5.5',
        broadcast => '6.6.6.6',
        netmask => '7.7.7.7',
        gateway => '8.8.8.8',
    },

);

while (my $line = <DATA>) {
    if (my ($interface) = ($line =~ /^interface=(\S+)/)) {
        print $line;
        if (exists $lookup{$interface}) {
            $line = process_interface(\*DATA, $lookup{$interface});
            redo;
        }
    }
    else {
        print $line;
    }
}

sub process_interface {
    my ($fh, $lookup) = @_;
    my $keys = join '|', sort keys %$lookup;

    while (my $line = <DATA>) {
        $line =~ s/\A($keys)=.+/$1=$lookup->{$1}/
            or return $line;
        print $line;
    }

    return;
}

__DATA__
#
# /etc/rc.conf - Main Configuration for Arch Linux

. /etc/archiso/functions

# stuff

interface=eth0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
interface=wlan0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
# # /etc/rc.conf - Main Configuration for Arch Linux . /etc/archiso/functions # stuff interface=eth0 address=1.1.1.1 netmask=3.3.3.3 broadcast=2.2.2.2 gateway=4.4.4.4 interface=wlan0 address=5.5.5.5 netmask=7.7.7.7 broadcast=6.6.6.6 gateway=8.8.8.8