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?
答:可以。
对于printfvs. echo这是可移植性的问题;参见为什么printf比echo好? 而且,使用可以在命令之间插入换行符也更容易printf。
对于printf ... | exvs. 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?
printfvs. 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场分隔符!