Answers:
在中,awk
您可以将字段分隔符设置为任何值。如果将其设置为C
,则字段+1的数量将为的数量C
。
所以,如果你说awk -F'C' '{print NF}' <<< "C1C2C3"
你4
:CCC
由3 C
秒,因此4个领域。
您要删除仅C
出现一次的行。考虑到这一点,在您的情况下,您将要删除恰好有两个- C
字段的那些行。因此,只需跳过它们:
$ awk -F'C' 'NF!=2' file
DTHGTY
HYTRHD
HTCCYD
awk 'BEGIN { print "FS={" FS"}","OFS={" OFS "}";} {printf "%d fields : ",NF; for (i=1;i<=NF;i++) {printf "{" $i "} ";}; print "" }'
并给它喂一些线,有些具有多个spces,而另一些则以空格开头)
这将删除仅出现一次C的行。
grep -v '^[^C]*C[^C]*$' file
正则表达式[^C]
匹配一个非C(或换行符)的字符,重复运算符(又名Kleene star)*
指定零个或多个前一个表达式的重复。
grep
(和大多数其他面向文本的工具)的默认输出为标准输出;重定向到新文件,如果需要的话,可以将其移动到原始文件的顶部。相同的正则表达式可用于sed -i
就地编辑:
sed -i '/^[^C]*C[^C]*$/d' file
(在某些平台上,特别是* BSD包括macOS,该-i
选项需要一个参数,例如-i ''
。)
sed -i '/^[^C]*C[^C]*$/d' file
-听起来好像是以前发布的,您怎么看,窃?
grep
答案开始,但显然很容易扩展到该sed -i
变体。没有找到您的答案,因为我一直在寻找以前的grep
答案。
-i
使用sed
,而是重定向到一个新文件,并用该文件替换原始文件,这样比较安全sed
。
grep -vx '[^C]*C[^C]*'
grep
它,因为它更清晰,更健壮(尤其是sed
信息量少的退出代码)。
用于脚本编辑文件(而不是将修改后的内容打印到标准输出中)的POSIX工具为ex
。
printf '%s\n' 'g/^[^C]*C[^C]*$/d' x | ex file.txt
当然,如果您的Sed版本支持该功能,则可以使用sed -i
,但要注意,如果要编写旨在在不同类型的系统上运行的脚本,则该功能是不可移植的。
大卫·佛斯特(David Foerster)在评论中问:
是否有一个原因,您正在使用
printf
,而不是echo
或类似的东西ex -c COMMAND
?
答:可以。
对于printf
vs. echo
这是可移植性的问题;参见为什么printf比echo好? 而且,使用可以在命令之间插入换行符也更容易printf
。
对于printf ... | ex
vs. ex -c ...
,这是一个错误处理问题。对于此特定命令,这无关紧要,但总的来说,它会起作用。例如,尝试将
ex -c '%s/this pattern is not in the file/replacement text/g | x' filename
在脚本中。与以下内容进行对比:
printf '%s\n' '%s/no matching lines/replacement/g' x | ex file
第一个将挂起并等待输入;当ex
命令接收到EOF时,第二个将退出,因此脚本将继续。还有其他解决方法,例如s///e
,但是POSIX未指定。我更喜欢使用上面显示的可移植表格。
对于g
命令,最后必须有一个换行符,并且我更喜欢使用printf
换行符而不是将换行符嵌入单引号中。
printf
,而不是echo
或类似的东西ex -c COMMAND
?
printf
vs. echo
(尽管通常我只喜欢echo
在参数经过硬编码的情况下使用),但ex
到目前为止我还没有广泛使用。
sed -e '
s/C/&/2;t # when 2nd C matches skip processing and print
/C/d # either one C or no C, so delete on C
'
sed -e '
/C/!b # no C, skip processing and print
/C.*C/!d # not(at least 2 C) => 1 C => delete
'
perl -lne 's/C/C/g == 1 or print'
sed
,t #...
通常会转移到所谓的标签#...
在大多数其他sed
的实现。
b
,t
,:
,}
(和r file
,w file
...)不能在他们之后的指令在同一行。您也可以使用单独的-e
选项。
g
修饰符。
对于任何想要的人awk
,我会提供
awk '/C[^C]*C/{next}//{print}'
如果与模式匹配,请跳过该行,否则将其打印。您实际上并不需要{print}
,您可以使用//
默认打印,但我认为它更清晰。
我的第一个想法是使用egrep -v
相同的模式,但实际上并没有回答所提出的问题。
{next}
?只需说一遍awk '/pattern/ {next} 1'
,所有与模式不匹配的行都将被打印。或者,最好awk '!/pattern/'
直接打印这些。
!/pattern/
(某种程度上让我无视了),但是我宁愿看到一个不言自明的说法,而//{print}
不是一个神秘的事物1
。假设下一个人维护您的代码的能力和流利程度最低,这与不使它的效率或效率严重降低保持一致。
awk
场分隔符!