如何修复 perl 中的错误变量替换

How to fix errorenous variable substitution in perl

我正在为一个只包含一个单词的 x 个第一个发音(以下简称 ngram)的单词识别程序创建几个词典。因此,我从现有词典中提取需要的词。但是,我想自动执行此操作,即找到 ngram 的所有单词(例如 ngram = 3),保存它们,增加 ngram(= 4)并重复该过程。代码如下所示:

ngrams=$(seq 3 1 9)
for ngram in $ngrams
do

cat /Lexicon/whole_lexicon.lex | perl -ne 'chomp; @tok = split(/\s+/); $ntoprint = $#tok; if ($ngram < $ntoprint) {$ntoprint = $ngram}; for ($i = 1; $i <= $ntoprint; $i++) {printf("%s\t%s\n", join("", @tok[1..$i]), join(" ", @tok[1..$i])); }' > lexicons/lex$ngram.txt

done

不幸的是,perl 无法识别值 $ngram,命令无法正常运行。作为比较,此脚本有效:

ngram=3
cat /Lexicon/whole_lexicon.lex | perl -ne 'chomp; @tok = split(/\s+/); $ntoprint = $#tok; if (3 < $ntoprint) {$ntoprint = 3}; for ($i = 1; $i <= $ntoprint; $i++) {printf("%s\t%s\n", join("", @tok[1..$i]), join(" ", @tok[1..$i])); }' > lexicons/lex$ngram.txt

经过一些研究,我现在知道我可以编写一个 perl 脚本并将变量值 $ngram 传递给这个脚本,我可以在其中与 @ARGV 一起使用它。但是,我正在寻找一个解决方案,这样我就可以 运行 在终端中输入一个命令。

Perl 无法访问 shell 的变量,并且 shell 无法更改单引号中的任何内容 - 这里没有 "invalid substitution" 因为这里根本没有替代品。解决方案是将值作为参数传递给 Perl,或者(不太理想)让 shell 将值注入 Perl 源代码,例如通过将 Perl 脚本的一部分从单引号切换为双引号。

for ngram in $(seq 3 1 9)
do
    perl -ne 'BEGIN { $ngram = shift @ARGV; }
        chomp;
        @tok = split(/\s+/);
        $ntoprint = $#tok;
        if ($ngram < $ntoprint) {$ntoprint = $ngram};
        for ($i = 1; $i <= $ntoprint; $i++) {
           printf("%s\t%s\n", join("", @tok[1..$i]), join(" ", @tok[1..$i]));
        }' "$ngram" < /Lexicon/whole_lexicon.lex > lexicons/"lex$ngram.txt"
done

这也删除了 useless cat 并修复了一个小的引用错误。

在您的原始代码中,$ngram 是一个 shell 变量。但是把它变成一个环境变量,Perl 就可以通过特殊的散列 %ENV.

来访问它
export ngram       # upgrade $ngram from shell to environment variable
for ngram in $ngrams
do

    perl -ne 'chomp; @tok = split(/\s+/); $ntoprint = $#tok; 
          if ($ENV{ngram} < $ntoprint) {$ntoprint = $ENV{ngram}};
          for ($i = 1; $i <= $ntoprint; $i++) {
              printf("%s\t%s\n", join("", @tok[1..$i]), join(" ", @tok[1..$i]));
          }' < /Lexicon/whole_lexicon.lex > lexicons/lex$ngram.txt

done