我有一个文本文件,如下所示:
A : 1
Boy : 3
Ahoy! : 7
more : 8
我必须删除长度小于或等于3个字母长的行。输出应如下所示:
Ahoy! : 7
more : 8
由于
答案 0 :(得分:1)
OP有点不明确(并且由于comm(ent | un)),根据我对问题的解释,我们发展了一些可能的解决方案。
我的1 st 脚本filter.awk
:
$3 <= 3 { next }
{ print $0 }
仅考虑3 rd 列(使用标准空白分隔)。因此,将冒号后的数字与常数3
进行比较。
您的测试输入filter.txt
:
A : 1
Boy : 3
Ahoy! : 7
more : 8
测试:
$ awk -f filter.awk filter.txt
Ahoy! : 7
more : 8
$
埃德莫顿指出,它可以做得更短:
$3 > 3
这对我来说也是新的。 (可能是,我对lex感到困惑,其工作方式相反:在lex / flex中,所有无法比拟的东西都会被回应。)
更强大的方法是使用冒号(:
)作为列分隔符(或者像在awk:field分隔符中命名的那样)。通过分配内置变量FS
可以实现更改字段分隔符。这可以使用命令行参数-F
或在特殊BEGIN
规则中的赋值来完成,该规则始终在开始时执行。 (我更喜欢写字母的字母&#34;自包含&#34;。)
因此,filter2.awk
(即filter.awk
V2.0):
BEGIN { FS = ":" }
$2 <= 3 { next }
{ print $0 }
或考虑我今天学到的东西:
BEGIN { FS = ":" }
$2 > 3
测试:
$ awk -f filter2.awk filter.txt
Ahoy! : 7
more : 8
$
对OP的另一种解释可能是考虑每行第一列中连续字母的数量。为实现这一目标,一些内置函数发挥作用:
gensub()
一个强大的替换函数,遗憾的是只在GNU awk中可用
length()
返回字符串的长度(或数组中元素的数量)
为此我使用扩展测试输入filter2.txt
:
A : 1
Boy : 3
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
Hi World : 0
filter3.awk
(即filter.awk
V3.0):
length(gensub(/(^[A-Za-z]+).*$/, "\\1", 1, $1)) > 3
测试:
$ awk -f filter3.awk filter2.txt
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
$
由于在这种情况下字段分隔符未更改,因此1 st 字段由直到1 st 空格的字符组成。模式(^[A-Za-z]+)
捕获文本开头的所有字母,并将它们存储到1个 st 内部缓冲区中。 .*$
匹配其余部分直到文本结尾。整个文本由缓冲区\1
替换。 (考虑"\\1"
中的转义反斜杠。)这对我在cygwin中的bash工作正常,因为我曾经在我的bash初始化中定义了LANG=C
(在遇到德语区域设置问题之后)。 Ed Morton(再次)指出使用[[:alpha:]]
代替[A-Za-z]
应该更加健壮。
如果您有非GNU awk,则gensub()
不可用。 (几个星期前,另一个大师(一个名字中有 k 的大师)告诉我,世界上没有其他的问题,而不是gawks。检查这一点,我意识到即使是awk在我们的公司中,Windows VS构建链实际上是一个傻瓜。然而,自从我了解到这一点后,我偶然发现我的答案没有很好地排除,因为我没有认为解决方案是明确的(或隐含的)非GNU awk所需...)
所以这是非GNU awk filter4.awk
的4 th 版本:
{
text = $1
gsub(/[^[:alpha:]].*$/, "", text)
if (length(text) > 3) { print $0 }
}
测试:
$ awk -f filter4.awk filter2.txt
Ahoy! : 7
more : 8
Hello World : 0
Hello! World. : 0
$
对于gsub()
,我恢复了reg-ex替换的逻辑:从第一个非alpha字符到文本结尾的所有内容都被空字符串替换。 (AFAIK,甚至不存在gsub()
中的枚举缓冲区。)
临时变量text
的赋值是必要的,因为gsub()
修改了其3 rd 参数的内容。如果我直接提供$1
(正如我在修复之前所做的那样),其内容将会更改,而这又会改变$0
的内容。