【问题标题】:Translating Bash to Perl将 Bash 转换为 Perl
【发布时间】:2017-06-20 17:31:31
【问题描述】:

我正在用 Perl 重写一个 bash 脚本。

原始脚本检查 Linux 软件包是否处于未配置状态,如果是,则删除并重新安装。

#!/bin/bash
if [[ $(dpkg -l | grep libc-bin | grep iF) || $(dpkg -l | grep libc-dev-bin | grep iU) ]] ; then
    echo "do something"
fi

我开始查看是否可以使用系统调用并将它们存储为变量,然后只运行这些多个变量的if 语句。这似乎不起作用。

#!/usr/bin/perl

my $libcUnconfigured    = system("dpkg -l | grep libc-bin | grep iF");
my $libcDevUnconfigured = system("dpkg -l | grep libc-dev-bin | grep iF");

if ( $libcUnconfigured || $libcDevUnconfigured ) {
    print "Do something";
}

【问题讨论】:

  • system 返回返回码,而不是输出。请改用qx//
  • 你为什么在 perl 中使用 grep?
  • 获取包列表:my @libcUnconfigured = grep { /libc-bin|iF/ } qx(dpkg -l)qx ("backticks") 返回一个列表,grep 过滤后得到一个列表(数组)。 qx 使用 /bin/sh 或系统为其提供的任何内容,因此您可能需要指定命令路径
  • @Borodin 现在无法解决...可能在一小时或几个小时内完成,除非届时有人将其覆盖。 (也很高兴从 OP 那里知道该评论是否足够。)如果您愿意,请务必回答。抱歉延迟回复
  • 这是一个坏主意。 Shell 提供了安全执行代码的工具——如果变量中有名称,则可以引用"$var"(引号),并确保它只会计算其文字内容——没有转义,没有重定向,没有命令替换或任意代码执行。当您开始从其他 shell 语言生成和执行 shell 脚本时,您需要竭尽全力从代码中带外传递数据,以保持同样的安全保证。因此,用其他语言包装 shell 脚本本身就容易出错,除非 100% 硬编码。

标签: bash perl if-statement conditional system


【解决方案1】:

为了接收来自外部命令的输出,请使用qx operator,而不是system,后者返回由wait 返回的程序退出状态。

我建议仅将外部程序用于您在 Perl 中无法完成的事情,或者在极少情况下,当它们极大地简化您的工作时。对于所有其他事情,请使用 Perl 广泛的处理能力。

在这种情况下,通过grep过滤来自dpkg -l的返回

my @libcUnconfigured = grep { /libc-bin|iF/ } qx(dpkg -l);

chomp @libcUnconfigured;

print "Do something with $_\n" for @libUnconfigured;

qxlist context 中使用时返回输出行列表,此处由grep 强加。 grep 中的代码块在一个元素上运行,每个元素在默认 $_ variable 中可用;默认情况下,正则表达式匹配在$_ 上完成。代码计算结果为 true 的项目通过并作为列表返回,这里分配给一个数组。

请注意,qx 使用 /bin/sh,通常归入系统上的另一个 shell。所以小心地把命令放在一起。请参阅链接文档和$? in perlvar 进行错误检查。

返回列表中的每一行输出都带有其换行符,假设对这些文件名进行了一些非平凡的处理,我将其删除。 (当然不需要chomp单独打印。)

或者,您可以访问多个模块之一。一个不错的是Capture::Tiny

use warnings;
use strict;
use feature 'say';

use Capture::Tiny qw(capture);

my @cmd = qw(dpkg -l);

my ($stdout, $stderr) = capture {
    system (@cmd);
};

warn "Error with @cmd: $stderr" if $stderr;

say "Do something with $_" for (split /\n/, $stdout);

因为它的简洁语法,它把错误交给我们的事实,以及它几乎可以运行任何代码的能力

Capture::Tiny 提供了一种简单、可移植的方式来捕获发送到 STDOUT 或 STDERR 的几乎所有内容,无论它来自 Perl、XS 代码还是来自外部程序。

这里的命令形成一个列表,允许system 绕过shell。这更好,除非您需要 shell。在这种情况下,返回的是一个(可能是多行)字符串,因此是 split 来处理带有包信息的行。

其他一些,在增加功能和使用复杂性方面,是IPC::Run3IPC::Run

另见this entry in perlfaq8。请注意,在某些示例中使用的IPC::Open3 相当低级。

【讨论】:

    猜你喜欢
    • 2015-10-16
    • 2014-06-14
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    相关资源
    最近更新 更多