Perl で find コマンドを発行し、結果のファイル パスをループ処理したいと考えています。私はそのようにしようとしています(しかし、運がありません):
my $cmd;
open($cmd, '-|', 'find $input_dir -name "*.fastq.gz" -print') or die $!;
while ($line = <$cmd>) {
print $line;
}
close $cmd;
何か案は?
ありがとう
Perl で find コマンドを発行し、結果のファイル パスをループ処理したいと考えています。私はそのようにしようとしています(しかし、運がありません):
my $cmd;
open($cmd, '-|', 'find $input_dir -name "*.fastq.gz" -print') or die $!;
while ($line = <$cmd>) {
print $line;
}
close $cmd;
何か案は?
ありがとう
*
キャラクターに十分なエスケープを適用していません。の前に\
付けると修正されます。
引数を分離して、そもそもシェルを呼び出さない方がよいでしょう。
use warnings;
use strict;
open(my $cmd, '-|', 'find', $input_dir, '-name' ,'*.fastq.gz', '-print') or die $!;
while (my $line = <$cmd>) {
print $line;
}
close $cmd;
あなたの問題は一重引用符を使用しているようです。変数は補間されませんが、変数名はそのままフィードさfind
れます。
しかし、なぜ使用しないのFile::Find
ですか?
> perl -MFile::Find -lwe '
$foo = "perl";
find ( sub { /\.pl$/i or return; print $File::Find::name }, $foo);'
perl/foo.pl
perl/parsewords.pl
perl/yada.pl
ここでのwanted
サブルーチンは、ファイル名に対する単純なパターン マッチです。拡張子が でない限り、サブルーチンを終了 (リターン) し.pl
ます。
あなたがするなら
print 'find $input_dir -name "*.fastq.gz" -print';
問題は明らかになるはずです。一重引用符は補間しません。あなたはおそらくするつもりだった
open(my $cmd_fh, '-|', qq{find $input_dir -name "*.fastq.gz" -print}) or die $!;
しかし、それもバグです。$input_dir
シェルリテラルに変換しません。2つの解決策があります。
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote("find", $input_dir, "-name", "*.fastq.gz", "-print");
open(my $cmd_fh, '-|', $cmd) or die $!;
または
my @cmd = ("find", $input_dir, "-name", "*.fastq.gz", "-print");
open(my $cmd_fh, '-|', @cmd) or die $!;
コマンドの出力を読み取るには、バックティック演算子を使用します。
my $command = "find $inputdir ..."; # interpolate the input directory
my $output = `$command`; # be careful here
my @lines = split /\n/ => $output; # split in single lines
for my $line (@lines) { # iterate
# do something with $line
}
パイピングよりもはるかに読みやすいと思います。欠点はブロックすることなので、大量の行を含む巨大な出力文字列を処理したい場合は、パイプ アプローチの方が適している可能性があります。
ただし、適切なモジュールを使用したい場合があります。File::Find (コア モジュール) がニーズに合うはずです。