当@array包含find命令时,为什么系统(@array)不起作用?

Cor*_*rni 2 perl

我开始喜欢Perl,但我不明白这里发生了什么.

为什么这样做

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));
Run Code Online (Sandbox Code Playgroud)

产量

find data/path/ -name *.xml -exec mv {} junk/path/ \;
Run Code Online (Sandbox Code Playgroud)

找不到错误!虽然这不起作用

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);
Run Code Online (Sandbox Code Playgroud)

输出:

find data/path/ -name *.xml -exec mv {} junk/path/ \;
find: Missing argument for »-exec«.
Run Code Online (Sandbox Code Playgroud)

system应该能够理解数组.看到这里.当我将输出复制到shell时,没有遗漏的参数,它只是起作用.但我的脚本无法执行此操作.

mob*_*mob 11

在第二个system电话中,你不应该逃避;.

-exec开关find吸食参数,直到找到一个;.;shell将其解释为命令分隔符,因此当您从命令行运行时find ... -exec,需要将其转义,并且在shell脚本中您将看到该模式

find ... -exec ... \;
Run Code Online (Sandbox Code Playgroud)

在第二次system调用中,您将收集数组中的所有参数并将数组直接传递给system.在这种情况下,Perl没有使用shell来解释命令,并且find命令看到的是参数\;而不是;,并且-exec开关变得混乱.

所有你需要说的是让你的system命令工作

...
push @cmd, ';';
...
system(@cmd);
Run Code Online (Sandbox Code Playgroud)

  • 因为在`system(@LIST)`中,`@LIST`的每个元素都被视为一个命令行参数.`find`支持一个名为`-exec`的开关,但它不支持名为`-exec mv {}`的开关.输入/输出重定向(`<file`,`> file`,`>> file`,`2>&1`,...)在shell中实现,而不是在底层系统调用中实现.`system(@LIST)`绕过shell,因此I/O重定向操作符被解释为正常的命令行参数,就像你说'cat*.xml'>>'summary.xml`一样. (3认同)

Thi*_*Not 5

暴徒指出了你的system电话当前的问题,但有一个更好的方法来做到这一点.您可以使用File :: Find :: Rule,它具有与find实用程序非常相似的接口,而不是执行外部命令:

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('.');
Run Code Online (Sandbox Code Playgroud)