我想从仅包含一次特定字符的文件中删除一行,如果它出现多次或不存在,则将该行保留在文件中。
例如:
DTHGTY
FGTHDC
HYTRHD
HTCCYD
JUTDYC
在这里,我要删除的字符是C
这样,命令应该删除行FGTHDC
,JUTDYC
因为它们只有C
一次。
我怎样才能使用sed
or来做到这一点awk
?
答案1
您awk
可以将字段分隔符设置为任何内容。如果将其设置为C
,那么您将拥有与 的出现次数一样多的字段 +1 C
。
所以如果你说awk -F'C' '{print NF}' <<< "C1C2C3"
你得到4
:CCC
包含 3C
秒,因此有 4 个字段。
您想要删除C
只出现一次的行。考虑到这一点,在您的情况下,您将需要删除那些恰好有两个C
- 字段的行。所以跳过它们:
$ awk -F'C' 'NF!=2' file
DTHGTY
HYTRHD
HTCCYD
答案2
sed方法:
sed -i '/^[^C]*C[^C]*$/d' input
-i
选项允许就地文件修改
/^[^C]*C[^C]*$/
C
- 匹配只包含一次的行
d
- 删除匹配的行
答案3
这可以通过以下方式完成sed
:
代码:
sed '/C.*C/p;/C/d' file1
结果:
DTHGTY
HYTRHD
HTCCYD
如何?
- 匹配并打印至少有两份
C
via的任意行/C.*C/p
- 删除带有
C
via的任何行/C/d
,这包括步骤 1 中已打印的行 - 默认打印其余行
答案4
用于对文件进行脚本编辑(而不是将修改的内容打印到标准输出)的 POSIX 工具是ex
.
printf '%s\n' 'g/^[^C]*C[^C]*$/d' x | ex file.txt
当然可以使用sed -i
如果您的 Sed 版本支持它,请注意,如果您正在编写旨在在不同类型的系统上运行的脚本,那么它是不可移植的。
大卫·福斯特在评论中问道:
printf
您使用and 不使用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
第一个将挂起并等待输入;当命令收到 EOF 时,第二个将退出ex
,因此脚本将继续。还有其他替代解决方法,例如s///e
,但 POSIX 未指定它们。我更喜欢使用便携式形式,如上所示。
对于g
命令来说,有必须最后是换行符,我更喜欢用它printf
来包装命令而不是在单引号中嵌入换行符。