【问题标题】:Passing arguments to system commands from perl从 perl 向系统命令传递参数
【发布时间】:2017-12-18 21:26:14
【问题描述】:

我正在编写一个使用一些 ImageMagick 命令的 perl 脚本,特别是识别。相关代码在这里:

my $height = system("identify -format %h $curPic");
my $width = system("identify -format %w $curPic");

当我运行整个脚本时,它会挂在这些行上,这是输出:

identify: unable to open image 'if0W211.jpg': No such file or directory @ error/blob.c/OpenBlob/3323
identify: unable to open image 'if0W211.jpg': No such file or directory @ error/blob.c/OpenBlob/3323

起初,问题与 ImageMagick 没有正确的格式代表来处理 jpg 图像有关,但在修复该问题后,我仍然收到此错误。我找不到任何与“error/blob.c/OpenBlob/3323”相关的错误文档。在编写了一些测试代码以查看问题可能是什么之后,我想我已经确定它与 perl 将参数传递给系统命令的方式有关,因为当我在终端中编写该系统命令 identify -format %h xxxx.jpg 时,它工作得很好。我还注意到,当我print "$curPic\n 时,在打印过程中文件名前面会附加一个 256。我不知道为什么会这样。

作为参考,以下是我收集文件名的方式:

opendir DIR, $folder or die "Cannot open directory: $!";
my @files = readdir(DIR);
closedir(DIR);

这是完整的脚本:

#!/usr/bin/perl -w

use strict;
use diagnostics;
use File::Copy;

my $folder = "/media/sf_Pictures_from_Reddit";
my $oriFolder = "/media/sf_WrongOrientation";
my $resFolder = "/media/sf_LowRes";

#Collect all the files
opendir DIR, $folder or die "Cannot open directory: $!";
my @files = readdir(DIR);
closedir(DIR);

#Iterate through each file and check its orientation and resolution
foreach my $curPic (@files) {
    my $height = system("identify -format %h $curPic");
    my $width = system("identify -format %w $curPic");

    #move those that are vertically oriented to a different folder
    if ($height >= ($width*0.8)) {
    move($curPic, $oriFolder//$curPic) or die "The ori move operation     failed for image $curPic: $!";
        print "$curPic was not approved because of its orientation.";
        next;
    }
    #move those that are low res to a third folder
    elsif (($height < 1080) | ($width < 1920)) {
    move($curPic, $resFolder//$curPic) or die "The res move operation     failed for image $curPic: $!";
        print "$curPic was not approved because of its resolution.";
        next;
    }
    print "$curPic is approved as a desktop background";
}

编辑: 我正在切换到推荐的 Image::Size 库,所以这是我更新的脚本。它工作了一段时间,给了我想要的输出,但突然中断并说变量未初始化。 “使用未初始化的变量...” $height 和 $width 有一个错误,但它们再次发生在大约 20 次成功迭代之后。如果我多次背靠背运行脚本,它似乎会有所不同。

#!/usr/bin/perl -w

use strict;
use diagnostics;
use File::Copy;
use Image::Size;

my $folder = "/media/sf_Pictures_from_Reddit";
my $oriFolder = "/media/sf_WrongOrientation";
my $resFolder = "/media/sf_LowRes";

my $height = 0;
my $width = 0;

#Collect all the files
opendir DIR, $folder or die "Cannot open directory: $!";
my @files = readdir(DIR);
closedir(DIR);

#Iterate through each file and check its orientation and resolution
foreach my $curPic (@files) {
    ($width, $height) = imgsize("$folder/$curPic");

    #move those that are vertically oriented to a different folder
    if ($height >= ($width*0.8)) {
        move("$folder/$curPic", "$oriFolder/$curPic") or die "The ori move operation failed for image $curPic: $!";
        print "$curPic was not approved because of its orientation.\n";
        next;
    }
    #move those that are low res to a third folder
    elsif (($height < 1080) | ($width < 1920)) {
        move("$folder/$curPic", "$resFolder/$curPic") or die "The res move operation failed for image $curPic: $!";
        print "$curPic was not approved because of its resolution.\n";
        next;
    }
    print "$curPic is approved as a desktop background.\n";
}

【问题讨论】:

  • 另外,使用带有列表而不是字符串的 system(或 open 等)以避免在 shell 内进行解释,例如system('identify','-format','%w',$curPic)
  • 顺便说一下,您应该将错误消息打印到 STDERR(而不是 STDOUT)。
  • 你是不是偶然发现了...stackoverflow.com/a/21203371/2836621

标签: perl imagemagick imagemagick-identify


【解决方案1】:

正如消息所说,您将路径传递给一个不存在的文件。而不是通过

if0W211.jpg

你应该过去了

/media/sf_Pictures_from_Reddit/if0W211.jpg

这仍然会给您带来以下问题:

  • 一个注入错误
  • 路径可能被误解为一个选项。
  • 缺乏错误处理
  • 缺少对程序输出的捕获。
  • 重复执行外部进程。

所有这些都可以通过使用Image::Size 来解决。

但如果你坚持使用identify

use IPC::System::Simple qw( capturex );

my $dimensions = eval { capturex("identify", "-format", "%h,%w", "--", "$folder/$curPic") }
    or do {
       warn("Can't determine the dimensions of \"$folder/$curPic\": $@");
       next;
    };

my ($height, $width) = $dimensions =~ /^(\d+),(\d+)$/
   or do {
       warn("Can't determine the dimensions of \"$folder/$curPic\": Unexpected output from \"identify\": $dimensions\n");
       next;
   };

如果您的identify 不支持--(或者即使支持),您可以替换

"--", "$folder/$curPic"

"$folder/$curPic" =~ s{^-}{./-}r

【讨论】:

  • 我对@9​​87654330@ 不是很熟悉,而"--" 您用来将文件名与参数分开可能是其中的一个功能,如果是这样,我很抱歉并将删除此评论。否则,identify 本身不接受 -- 作为参数结束的标记。
  • 它告诉identify 剩下的参数不是选项。或者至少在我的机器上是这样。
  • 哦,有趣,在 macOS 和 ImageMagick 版本 7.0.7 下,如果我运行 identify -format %h -- a.jpg 我会得到 identify: unrecognized option "--" @ error/identify.c/IdentifyImageCommand/920.
  • @Mark Setchell,在这些方面,您需要类似 "$folder/$curPic" =~ s{^-}{./-}r 而不是 "--", "$folder/$curPic"
  • 我只是在终端中输入了它,没有涉及 Perl。
【解决方案2】:

就目前而言,您正在为每个图像创建两个新进程(一个用于识别宽度,另一个用于识别高度),因此如果您有大量图像,这可能会给您的系统带来相当大的负载。

作为替代方案,您可以只调用一个 identify 进程并将所有图像名称传递给它,如下所示:

identify -format "%w:%h:%f\n" *jpg

样本输出

2000:1200:ok.jpg
1200:2000:toolow2.jpg
1000:500:vert.jpg

然后您可以使用 bashPerl 解析它:

#!/bin/bash

VERT="/tmp"
TOOLOW="/tmp" 

identify -format "%w:%h:%f\n" *jpg | 
   while IFS=: read w h name; do
      echo "DEBUG: $name, $w, $h"
      [[ $h -gt $(( (8*w)/10 )) ]] &&         { mv "$name" "$VERT";   >&2 echo "Too tall: $name"; continue; }
      [[ ($h -lt 1080) || ($w -lt 1920) ]] && { mv "$name" "$TOOLOW"; >&2 echo "Low res: $name";  continue; }
      echo "$name approved"
   done

【讨论】:

    【解决方案3】:

    这是适用于我目的的最终脚本。我添加了定义检查和非零检查,以确保变量在继续之前接收到正确的输入。

    #!/usr/bin/perl -w
    
    use strict;
    use diagnostics;
    use File::Copy;
    use Image::Size;
    
    my $folder = "/media/sf_Pictures_from_Reddit";
    my $oriFolder = "/media/sf_WrongOrientation";
    my $resFolder = "/media/sf_LowRes";
    
    my $height = 0;
    my $width = 0;
    
    #Collect all the files
    opendir DIR, $folder or die "Cannot open directory: $!";
    my @files = readdir(DIR);
    closedir(DIR);
    
    #Iterate through each file and check its orientation and resolution
    foreach my $curPic (@files) {
    
        ($width, $height) = imgsize("$folder/$curPic") or die "Couldn't get the image dimensions for $curPic: $!";
    
        if($curPic eq "." || $curPic eq ".."){ next;}
        if((defined $height) & (defined $width)){
            if(($height != 0) & ($width != 0)) {
    
                print "File: $curPic\nHeight: $height\nWidth: $width\n";
                #sleep(0.5);
    
                #move those that are vertically oriented to a different folder
                if($height >= ($width*0.8)) {
                    move("$folder/$curPic", "$oriFolder/$curPic") or die "The ori move operation failed for $curPic: $!";
                    print "$curPic was not approved because of its orientation.\n\n";
                    next;
                }
                #move those that are low res to a third folder
                elsif(($height < 1080) | ($width < 1920)) {
                    move("$folder/$curPic", "$resFolder/$curPic") or die "The res move operation failed for $curPic: $!";
                    print "$curPic was not approved because of its resolution.\n\n";
                    next;
                }
                print "$curPic is approved as a desktop background.\n\n";
                $height = 0;
                $width = 0;
            }
            else{
                print "Variables failed to initialize.\n\n";
            }
        }
        else{
            print "Variables are undefined.\n\n";
        }
    }
    

    【讨论】:

    • 您的elsif 也可能是if,因为在备用前一个分支上有一个next,它也缺少第二个|
    猜你喜欢
    • 1970-01-01
    • 2018-04-07
    • 2023-04-01
    • 2015-04-05
    • 2016-12-28
    • 2011-05-23
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多