2017-02-07 6 views
2

私はPerlを愛し始めていますが、ここで何が起こっているのか分かりません。@arrayにfindコマンドが含まれているとシステム(@array)が動作しないのはなぜですか?

なぜこの作品が出力

find data/path/ -name *.xml -exec mv {} junk/path/ \; 

検索からエラーなし

my @cmd =(); 
push @cmd, 'find'; 
push @cmd, 'data/path/'; 
push @cmd, "-name"; 
push @cmd, '*.xml'; 
push @cmd, '-exec'; 
push @cmd, 'mv'; 
push @cmd, '{}'; 
push @cmd, 'junk/path/'; 
push @cmd, '\;';  
say join (' ', @cmd);  
system(join(' ', @cmd)); 

ん!これは動作しませんが

my @cmd =();  
push @cmd, 'find'; 
push @cmd, 'data/path/'; 
push @cmd, "-name"; 
push @cmd, '*.xml'; 
push @cmd, '-exec'; 
push @cmd, 'mv'; 
push @cmd, '{}'; 
push @cmd, 'junk/path/'; 
push @cmd, '\;';  
say join (' ', @cmd);  
system(@cmd); 

出力:

find data/path/ -name *.xml -exec mv {} junk/path/ \; 
find: Missing argument for »-exec«. 

systemは配列を理解することができるはずです。 hereを参照してください。シェルに出力をコピーすると、引数が足りないので、うまくいきます。しかし、私のスクリプトはこれを実行できません。

+0

が、それはあなたの第2のプッシュ(データ/パスについては、/)を持っていないことをタイプミスです:代わりに外部コマンドを実行するには、findユーティリティと非常によく似ているインターフェイスを備えていFile::Find::Ruleを、使用することができます最初のケースで引用しますか? – AntonH

+2

サイドノート:これらの 'push 'ステートメントの代わりに' my @cmd = qw(データ/パス/ -name * .xml -exec mv {}ジャンク/パス/ \;); 'を実行することができます。 – ThisSuitIsBlackNot

+0

^^(あなたのパスに空白が含まれていないと仮定します) – ThisSuitIsBlackNot

答えて

10

第2のsystemコールでは、;をエスケープしないでください。

findへのスイッチ;が見つかるまで、-execに切り替えます。 ;は、コマンドの区切りとして、シェルによって解釈されるため、コマンドラインからfind ... -execを実行したとき、あなたはそれをエスケープする必要があり、シェルスクリプトで、あなたの第二system呼び出しでパターン

find ... -exec ... \; 

が表示されます配列内のすべての引数を収集し、配列を直接systemに渡します。この場合、Perlはコマンドを解釈するためにシェルを使用しておらず、findコマンドは、;の代わりに\;を参照し、-execスイッチは混乱します。

あなたが仕事にあなたのsystemコマンドを取得すると言うする必要があるのは

... 
push @cmd, ';'; 
... 
system(@cmd); 
+0

なぜ 'exec'と' mv {} 'や' name'と ' 'は同じ配列値にとどまることができませんか?その後、同様の構文解析エラーがスローされます。私は 'cat * .xml >> summary.xml'にもこのような問題があります。 – Corni

+2

'システム(@LIST)'では、 '@ LIST'のすべての要素が単一のコマンドライン引数として扱われます。 'find 'は' -exec'と呼ばれるスイッチをサポートしますが、 '-exec mv {}'と呼ばれるスイッチはサポートしていません。入出力リダイレクション( 'ファイル'、 '>>ファイル'、 '2>&1'、...)は、基本的なシステムコールではなく、シェルで実装されています。 'system(@LIST)'はシェルをバイパスするので、 'cat * .xml '>>' summary.xml'と同じように、I/Oリダイレクト演算子は通常のコマンドライン引数として解釈されます。 – mob

5

mob pointed outあなたsystem呼び出しで当面の問題ですが、これを行うには良い方法があります。

use strict; 
use warnings 'all'; 

use File::Copy; 
use File::Find::Rule; 

my $dest = '/foo/bar'; 

File::Find::Rule->file 
       ->name('*.xml') 
       ->exec(sub { move($_, $dest) or warn "move($_, $dest) failed: $!" }) 
       ->in('.'); 
+0

ありがとうございますが、 'Suse'にインストールするのは難しいかもしれないので、モジュールを避けることにします。私の決断ではない。 – Corni

+0

@Corniコアモジュール[File :: Find](http://perldoc.perl.org/File/Find.html)を使用することもできますが、インタフェースはあまり良くありません。純粋なPerlで簡単にできることをするために外部プログラムに頼るべきではありません。なぜなら、プログラムの移植性が低くなり、デバッグやエラー処理が難しくなるからです。 – ThisSuitIsBlackNot

+0

あなたは正しいです。私の 'システム'コールの多くは期待通りに動作しません。 'File :: Find :: Rule 'を使うことができるなら、私たちの管理者に話しましょう。 – Corni

関連する問題