我正在尝试在perl脚本中使用awk语句,该脚本接受用户输入并搜索许多文本文件,以查找以任何顺序匹配输入中所有单词的行。为此,我能够在CLI上进行我想要的Awk搜索:
awk 'tolower($0) ~ / 204/ && / test/ && / leg/' *_Codes.txt
这将返回引用文本文件中的行,其中包含以“204”,“test”和“leg”开头的单词,例如“在2045房间测试左腿”;
但是,当我尝试在Perl脚本中执行此操作时,将用户输入设置为变量并将其修改为包含&&
运算符和斜杠,我没有收到任何回复。这就是我所拥有的:
my ($code_search, $code_set) = @_;
# Clean the input for awk
# trim whitespace from the ends
$code_search =~ s!(^\s+|\s+$)!!g;
# separate words with the && operator and slashes
$code_search =~ s!\s+!/ && / !g;
# make input lower case and tack on front and back slashes
my $sanitized_query = lc "/ ${code_search}/";
# at this point, a user input of '204 leg test'
# is transformed to '/ 204/ && / leg/ && / test/'
# and is saved to the $sanitized_query variable
# run the query through awk and save it to $results
my $results = `awk 'tolower($0) ~ \$sanitized_query' *_Codes.txt`;
但是$results
并没有给我任何东西。
也许awk不是这里工作的合适工具,但它似乎比grep更适合我的需求,因为我想确保我可以搜索所有输入的术语并返回它们全部出现的结果任何顺序的一行文字。
非常感谢任何帮助。
答案 0 :(得分:6)
为什么不完全使用perl,而不是使用awk?您应该能够打开文件,读入每行并在正则表达式匹配时将其打印出来。正则表达式是perls最好的优势之一,为什么不直接利用它们而不是试图调用awk?
我看到使用awk的唯一好处是你必须手动列出所有的* _Codes.txt文件,但这在perl中应该不会太难。
在perl中执行此操作的最简单方法(假设您有一行文本),只需运行正则表达式3次,每次尝试匹配一个部分。例如,如果您想匹配204
,test
和leg
,您应该可以
if (($line =~ m/ 204/i) && ($line =~ m/ test/i) && ($line =~ m/ leg/i)){
print $line;
}
答案 1 :(得分:3)
$0
也是Perl中的有效符号(它包含当前运行的Perl脚本的名称),并且也在反引号内插值。你也需要逃避它:
my $results = `awk 'tolower(\$0) ~ \$sanitized_query' *_Codes.txt`;
答案 2 :(得分:2)
Pure Perl解决方案,包括拆分$code_search
,整理文件名,以及仅在单词的开头匹配模式:
use List::MoreUtils qw{ all };
my @words = ($code_search =~ m/\S+/g);
for my $fn (glob('*_Codes.txt')) {
open my $f, '<', $fn || die "Can't open: $!";
while (defined(my $line = <$f>)) {
if (all { $line =~ m{\b\Q$_\E}is } @words) { print $line }
}
close $f;
}
如果您不想依赖List :: MoreUtils,请将'if'更改为:
if (!grep { $line !~ m{\b\Q$_\E}is } @words) { print $line }
- 有点难以阅读,但只使用perl builtins。
答案 3 :(得分:2)
在@mob所说的基础上,我认为这是一个逃避问题。 不过,他的逃避太多了。你需要的是这样的:
my $results = `awk 'tolower(\$0) ~ $sanitized_query' *_Codes.txt`;
您希望$0
是文字的,但要插入$sanitized_query
。 (在上面的代码示例中,您正在逃避错误的代码)。
答案 4 :(得分:1)
虽然Skolor的答案是完全合适的,但这是一种略有不同的方法,使用smart match operator(可在Perl版本5.10或更高版本中使用)。如果你的文本文件的行很长,如果你没有很多单词来检查这些行,这可能是一个更快的方法(强调“可能”)。
use strict;
use warnings;
my @query_words=qw(204 test leg);
open(my $read,"<","input_file") or die $!;
while(<$read>)
{
chomp; #get rid of trailing newline
my @words=split(/\s+/,$_); #split on spaces to get actual words
foreach my $q (@query_words)
{
if($q~~@words) #If we have a match, print and exit the loop.
{
print "$_\n";
last;
}
}
}
close($read);