我发现我们可以使用
perl -wnle "/RE/ and print"
例如
perl -wnle "/^.{0,80}$/ and print"
或者
grep -ri someText * | perl -wnle "/^.{0,80}$/ and print"
排除长度超过 80 个字符的行。
但是如何将其设置为 Bash 中的别名呢?
我试过:
alias pgrep='perl -wnle "/$1/ and print"'
进而
grep -ri someText * | pgrep "^.{0,80}$"
但它会说
Can't open ^.{0,80}$: No such file or directory.
答案1
alias
在bash
是不是旨在接受参数,并且如果提供参数,则不知道如何处理它。通常应避免使用它们,并且仅应将它们用于非常简单的命令名称替代。
建议使用函数代替。请注意,这pgrep
是一个有效的 Linux 二进制文件,不应使用,建议使用明确的名称。
perlgrep() {
perl -wnle "/$1/ and print"
}
现在称其为
perlgrep '^.{0,80}$'
但错误的原因是,由于alias
无法传递参数本身,当扩展发生时,命令变成这样
grep -ri someText * | perl -wnle "/$1/ and print" '^.{0,80}$'
这是不正确的,因为perl
将'^.{0,80}$
其视为需要打开并运行正则表达式的文件名。
答案2
请注意pcregrep
(从PCRE库)和 GNU grep -P
(当使用 PCRE 支持构建时)可以采用类似 perl 的正则表达式,并且grep -P
在 UTF-8 语言环境中可以正常处理 UTF-8 数据。
如果您想使用perl
它,您可以定义一个脚本或函数来执行此操作。别名不行,因为别名只是别名,只是将一个字符串替换为另一个字符串。
你可以这样做:
perlgrep() (
export RE="${1?}"; shift
exec perl -Mopen=locale -Twnle '
BEGIN {$ret = 1; $several_files = @ARGV > 1}
if (/$ENV{RE}/) {
$ret = 0;
print $several_files ? "$ARGV: $_" : $_
}
END {exit $ret}' -- "$@"
)
但要小心perl -n
在任意文件名上运行的影响上述选项只能部分缓解这些问题-T
。
另外,使用-Mopen=locale
,我们将根据语言环境的字符集解码输入并编码输出,但文件名本身将是编码的但不是已解码,这意味着如果文件名的字节值高于 127,则除非语言环境的字符集为 iso8859-1,否则将无法正常工作。
最后,你只需要解码仅用于匹配的输入行。您不需要重新编码它,也不需要解码/编码文件名。
因此,使用最新版本的perl
,您可以执行以下操作:
#! /usr/bin/perl --
use warnings;
use strict;
use Encode::Locale;
use Encode;
my $re = shift @ARGV;
my $several_files = @ARGV > 1;
my $ret = 1;
while (<<>>) {
if (decode(locale => $_) =~ $re) {
$ret = 0;
print $several_files ? "$ARGV: $_" : $_
}
}
exit $ret;
为了防止从参数注入任意代码,禁用了(?{code})
,等正则表达式运算符。如果您希望它们回来,您可以在该脚本的顶部(??{code})
添加。use re 'eval';