Назад | Перейти на главную страницу

Как выполнить однострочник Perl из сценария Perl (с правильным экранированием)

У меня есть perl-скрипт, из которого мне нужно выполнить простой однострочный perl-файл на удаленном хосте:

ssh 192.168.1.1 "perl -pi.bup -e 's/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/' /etc/grub.conf"

Это просто добавляет "audit=1"до конца каждой строки ядра в /etc/grub.conf если он еще не существует.

Однострочник отлично работает при запуске непосредственно на хосте, но не при выполнении через ssh из другого скрипта Perl. Я попытался избежать всех знаков доллара с помощью одной или нескольких обратных косых черт, а также попытался избежать обратной косой черты в "\s", но я ничего не делаю, похоже, не работает.

Обратите внимание: я не хочу копировать скрипт на удаленный хост, а затем выполнять его - я хотел бы сделать это напрямую с помощью команды ssh.

Как правильно этого избежать, чтобы это работало?

- Обновление 9/9/2015, чтобы точно показать, что я делаю в сценарии perl:

sub SomeMethod
{
   &RunCommand($host, "perl -pi.bup -e \'s/^(\s+?kernel)(.*)(?<!audit=1)\$/\$1\$2 audit=1/\' /etc/grub.conf");
}

sub RunCommand
{
    my ($server, $command) = @_;
    my $commandOutput = "";

    if ($server ne "")
    {
        $command = "ssh $server \"$command\"";
    }

    $commandOutput = `$command`; 
    print $commandOutput;

    if (($? >> 8) != 0)
    {
        &LogMessage ("$command failed:\n\n$commandOutput");
        return $commandOutput;
    }
    return $commandOutput;
}

- Обновление №2, используя system вместо обратных тиков:

system 'ssh', $host, 'perl', '-pi.bup', '-e', 's/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/', '/etc/grub.conf';
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `perl -pi.bup -e s/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/ /etc/grub.conf'

Хорошо, я могу использовать систему здесь, но как правильно от нее избавиться ??

Поскольку вы редактируете удаленный файл на месте, вам не нужно записывать вывод, поэтому system было бы предпочтительнее, чем использование обратных кавычек:

system 'ssh', '192.168.1.1', 'perl', '-pi.bup', '-e', 's/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/', '/etc/grub.conf';

Обратите внимание, что вам не нужно передавать удаленную команду в качестве единственного параметра для ssh. Это немного помогает цитированию. Если вы действительно этого хотите, вы можете:

system 'ssh', '192.168.1.1', q{perl -pi.bup -e 's/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/' /etc/grub.conf};

Используя q{} чтобы разрешить однострочному Perl использовать однострочные кавычки.


Я бы сделал это на самом деле:

use Try::Tiny;
use IPC::System::Simple qw{capture};

sub SomeMethod
{
    my $output = RemoteCommand(
                    $host, 
                    q{perl -pi.bup -e 's/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/' /etc/grub.conf}
                );
}

sub RemoteCommand
{
    my ($server, $command) = @_;
    my $output;

    try {
        $output = capture('ssh', $server, $command);
    }
    catch {
        LogMessage("command failed: ($command) : $_");
        $output = $_;
    };

    return $output;
}

Я попробовал следующую простую команду, и она работает

ssh localhost "sed -i.bck '/[^audit]/{s/\(^\s\+kernel.*\)/\1 audit=1/g}' /boot/grub/menu.lst"

Не о sed vs perl, но с помощью предыдущей команды проще архивировать то, что вы хотите.

Наконец-то это заработало.

Из bash напрямую:

echo 's/^(\s+?kernel)(.*)(?<!audit=1)$/$1$2 audit=1/' | ssh 192.168.1.1 "perl -pi.bup - /etc/grub.conf"

Из сценария perl:

my $command = "echo 's/^(\\s+?kernel)(.*)(?<!audit=1)\$/\$1\$2 audit=1/' | ssh $_wsAddress 'perl -pi.bup - /etc/grub.conf' ";
&RunCommand("", $command);