1

I want to look for a string in all the files in a directory in perl. But the following code is not working

if ($^O eq "MSWin32") {
my @results = `findstr /s "Hello" /d:\\Testing`;
print "my results \n @results\n";
#or 
system('findstr /s "Hello" /d:\\Testing');
}

I am running the script from "C:" and it contains "Testing" directory. For the non windows system it works perfectly fine using grep system command. Please help. Thanks

4

5 回答 5

1

没有正确使用findstr

  1. 顺序很重要:开关/选项应该在参数(搜索字符串)之前(见输出findstr /?
  2. 指定要搜索的文件的参数是必需参数(此参数允许使用通配符)。

考虑到所有这些,一个有效的findstr命令将是

findstr /s /d:"Testing" *

如果您只需要包含匹配项的文件名(而不是匹配项文件中的行内容),请使用/m开关

findstr /s /m /d:"Testing" *

/s如果您不需要递归搜索,也不需要开关(例如搜索C :\Testing的子目录)

要注意的另一件事是,如果您使用/d:"Testing",输出的第一行将是

Testing:

最终将成为数组中的第一个元素。为了解决这个问题,您可以shift将您的数组,或者更好的是,将工作目录更改为在 Perl 中进行测试。

下面的代码片段显示了我将如何重写它

#!/usr/bin/env perl

use strict;
use warnings;

if ($^O eq "MSWin32") {
    chdir("Testing");
    my @results = qx'findstr /s /m "Hello" *';
    local $" = ", ";
    @results = map { s/^/Testing\\/; chomp; $_ } @results;
    chdir("..");
    print "my results \n@results\n";
}

其他注意事项(上帝,这篇文章已经太长了!):

  • qx'...'有点等价于,`...`除了两者之间的任何内容都不会被插值。
  • $"是用于数组元素的分隔符,当数组插入到双引号中时 a printor say(一旦代码工作,更改其值以查看它的作用)
  • map数组的每个元素进行一些处理
    • s/^/Testing\\/为每个文件名添加前缀“ Testing**”(这样您的结果将是 **relative to C:而不是相对于 Testing)
    • chomp从结果中删除尾随空白字符(例如换行符)
    • 最后$_确保它返回修改后的文件名(而不是返回值s///是#substitution)

您可以更进一步,在代码中参数化文件夹名称(“ Testing ”)和要搜索的字符串,甚至获取用户对这些参数的输入。但这留给读者作为练习(因为我累了,帖子已经太长了)

于 2013-07-19T04:03:33.853 回答
0
findstr /s "Hello" /d:\\Testing

指定一个 UNC 路径,即在名为Testing. 使用单个反斜杠指定目录。但我不确定这也是你想要的

findstr /s "Hello" /d:\Testing

指定Testing当前驱动器根目录下的目录,即C:\Testing. 如果要指定当前Testing目录下的目录,那么就是

findstr /s "Hello" /d:Testing

如果你也发现findstr自己很喜怒无常,你可能会有更好的运气,比如

findstr /s "Hello" /d:Testing\*

但当然,真正的解决方案是安装 DWIM 工具ack,尽管您无法使用 CPAN 库

于 2013-07-18T22:38:50.817 回答
0

我想你可能想试试http://search.cpan.org/~mneylon/File-Grep-0.02/Grep.pm

此外,在为 Linux 和 Windows 编写跨平台函数时,我倾向于将其包含在我的脚本顶部,以涵盖我可能会做的任何特定于 Windows 的事情:

BEGIN { # include additional Win32 specific modules when running on MS platforms
  if ($^O =~ /Win32/) {
    require Win32::AdminMisc; import Win32::AdminMisc;
    require Win32::API; import Win32::API;
    require Win32::GUI; import Win32::GUI;
    $wincon=Win32::GUI::GetPerlWindow();
  }
}

# your code starts here
于 2013-07-18T21:55:58.480 回答
0

文档来看findstr您的findstr选择似乎有些混乱;/d不带参数,并且看起来需要在搜索字符串和开始路径之前出现开关。所以试试这个:

findstr /d /s "Hello" \\Testing

代替findstr您当前使用的命令,您可能会发现更好的结果。

于 2013-07-18T21:55:59.743 回答
0

您的调用findstr挂起,因为您没有提供要匹配的全局模式。

考虑使用类似于

if ($^O eq "MSWin32") {
  my @results = `findstr /s /p /d:C:\\Testing "Hello" *.*`;
  die "$0: findstr failed" if $?;

  if (@results) {
    print @results;
  }
  else {
    warn "$0: no results\n";
  }
}

笔记:

  • 最大的变化是*.*在命令末尾添加了。
  • findstr通过检查$?而不是盲目地假设成功来检查是否成功运行。
  • /p选项告诉findstr跳过带有不可打印字符的文件。您可能希望也可能不希望保留此选项。
于 2013-07-19T00:21:48.180 回答