find
コマンドが常に指定されたディレクトリではなくルートディレクトリに移動する理由を誰でも教えてもらえますか$srceDir
?
my $srceDir = "/mnt/SDrive/SV/Capture Data/";
my $find_cmd = 'find $srceDir -type f -newermt 2013-02-14 ! -newermt 2013-02-15';
open(FIND_FILE, "$find_cmd |");
while(<FIND_FILE>){
next if /^total/; # because we're only interested in real output
print $_;
}
答え1
これは二重引用符の代わりに一重引用符を使用するためです。
Perlはそうではありません一重引用符で囲まれた変数の挿入だから、あなたがすることは '$ srceDir'文字列をシェルに送ることです。この文字列は、環境のどこかに設定しない限り、通常は設定解除(空)されます。
この試み:
my $find_cmd = "find $srceDir -type f -newermt 2013-02-14 ! -newermt 2013-02-15";
または、より良い方法は次のとおりです。
my $find_cmd = sprintf
'find "%s" -type f -newermt 2013-02-14 ! -newermt 2013-02-15',
$srceDir;
...空間に配慮しながら検索コマンドforkedで実行されますsh
。
*重要事項*
@vonbrandが正しく言及したように:真珠プログラムと他の多くのものとの間の通信を確実にするために、実際には多くのライブラリが提供されている。
ファイルシステムを操作するために、find
PerlはFile
ライブラリモジュールを使用します。これを行うには、コマンドラインを小さなPerlスクリプトに変換する小さなFile::Find
ユーティリティがあります。find2perl
find
$ find2perl -type f -mtime -3 ! -mtime -2;
#! /usr/bin/perl -w
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if 0; #$running_under_some_shell
use strict;
use File::Find ();
# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.
# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
sub wanted;
# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '.');
exit;
sub wanted {
my ($dev,$ino,$mode,$nlink,$uid,$gid);
(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
-f _ &&
(int(-M _) < 3) &&
! (int(-M _) < 2)
&& print("$name\n");
}
したがって、お客様の要件は次のとおりです。
#! /usr/bin/perl -w
my $srceDir = "/mnt/SDrive/SV/Capture Data/";
my $startDate = "2013-02-14";
my $endDate = "2013-02-15";
use strict;
use File::Find ();
use POSIX qw|mktime|;
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
my ($sDay,$eDay)=map {
my ($year,$month,$day)=split("-",$_);
(time()-mktime(0,0,0,$day,$month-1,$year-1900))/86400
} ($startDate,$endDate);
sub wanted {
my ($dev,$ino,$mode,$nlink,$uid,$gid);
(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
-f _ &&
(-M _ < $sDay) &&
! (-M _ < $eDay)
&& print("$name\n");
}
File::Find::find({wanted => \&wanted}, $srceDir );
これの最大の利点は、open $fh,"find ...|"
非常に強力であることです。ファイル名の文字(スペース、引用符、アンパサンドなど)に気を付ける必要はありません。
答え2
シェルメタ文字(スペースなど)を含む文字列をコマンドに指定すると、シェルのコマンドラインとして解釈されます。これは次の2つを意味します。
- 追加のコマンドを実行する必要があります(コマンドラインを解析するためのシェル)、これはあまり効率的ではありません。一部のシェル実装では、これは追加のプロセスを意味することもあります。
- 特殊文字をシェルにエスケープする必要があります。
パラメーター・リストを作成するためにコマンド行を分割するようにシェルに要求するよりも、パラメーター・リストを提供してコマンドを直接実行する方がよいでしょう。
また、以下を使用しないと、-print0
出力を安全に後処理することはできません。find
同様の質問に対する私の答え、次のように書く必要があります。
my $srceDir = "/mnt/SDrive/SV/Capture Data";
my @find_cmd = ("find", $srceDir, "-type", "f", "-newermt", "14 Feb 2013", "-print0");
open FIND, "-|", @find_cmd;
$/ = "\0"; # set perl's record separator
while (<FIND>) {
...
}
close FIND or warn $! ?
"Error closing find pipe: $!" :
"find exited with non-zero exit status: $?";
(しかし、ラインをfind
出力しないとtotal
混乱する可能性がありますls
。)