如果列4是匹配的,sed替换列9;否则用别的东西替换第9列

  • 本文关键字:替换 9列 sed 如果 shell unix awk sed
  • 更新时间 :
  • 英文 :


当读取一个非常大的以制表符分隔的文件时,该文件看起来像:

.   .   .   A   .   .   .   .   3:.:.:20
.   .   .   B   .   .   .   .   4:.:30
.   .   .   C   .   .   .   .   5:.:.:40:.
.   .   .   D   .   .   .   .   .:.:.:.
.   .   .   A   .   .   .   .   7:.:.:21
.   .   .   B   .   .   .   .   .:.:.:.
.   .   .   D   .   .   .   .   .:.:.:.
.   .   .   C   .   .   .   .   .:.:.

我想把第9列保留为。:.:.:。对于所有其他列4的值,我有一个单独的sed替换查询。所需的输出如下所示:

.   .   .   A   .   .   .   .   1:.:.:80
.   .   .   B   .   .   .   .   1:.:80
.   .   .   C   .   .   .   .   1:.:.:80:.
.   .   .   D   .   .   .   .   .:.:.:.
.   .   .   A   .   .   .   .   1:.:.:80
.   .   .   B   .   .   .   .   1:.:.:80
.   .   .   D   .   .   .   .   .:.:.:.
.   .   .   C   .   .   .   .   1:.:80

我现在的伪代码是这样的:

if [column 4 = D]
then
# either replace or just keep original entry
sed '/some replacement query/g' {file}
else
sed '/some other replacement query/g' {file}
fi

我在想,如果我可以在文件中一行一行地读取,也许我可以采用这种方法?但是我又不断地写更新新文件。

我不太确定如何在shell环境中有效地做到这一点。由于最终目标是创建一个大的结束文件,所以我当前的路由创建了两个不同的不正确的版本。也许有一种方法可以在单个sed查询中完成我想要的操作?但那超出了我的专业范围。

编辑:sed替换查询当前查看第9列,并确定字段分隔符的数量(":")并将其替换为相应的值,即3:.:.:20变为1:.:.:80,4:.:30变为1:.:80,5:.:.:40:.变为1:.:.:80:.。字段分隔符之间的值可以是数字0-99或";价值。但是,如果列4 = N,列9必须变成(或者在本例中保持不变).:.:.:.我当前的替换查询将.:.:.:.变成1:.:.:80,这是我不想要的。

sed 's/t(.|[0-9]):(.|([0-9]+)):(.|([0-9]+)):(.|([0-9]+))$/t1:.:.:80/g; 
s/t(.|[0-9]):([0-9],[0-9]):(.|([0-9]+)):(.|([0-9]+)):(.|([0-9]+))$/t1:.:.:80:./g; 
s/t(.|[0-9]):(.|([0-9]+)):(.|([0-9]+))$/t1:.:80/g'

awk通常在面向领域的东西上更好,但它可以完成sed:除非列4是D提取列9,编辑和附加作为第10列,最后删除第9列。

编辑更新为使用:作为子字段分隔符(是/)。
EDIT2:澄清t不是POSIX或macos。

sed -E -e '
/^([^t]*t){3}Dt/b            # special case: dont edit if D in column 4
h                               # copy line to hold space
s/^([^t]*t){8}([^t]*).*/2/  # set pattern space = column 9
s/^[^:]+/1/                     # set first subfield = 1
/([0-9]+){2}|[^:]+$/ s//80/     # set 2nd digit group or last subfield = 80
x                               # exchange pattern and hold spaces
G                               # append n+hold space to pattern space
s/n/t/                        # replace n with field separator
s/[^t]*t//9                   # delete (old) column 9
' -- file

额外的评论:

  • 选项卡是字段分隔符;如果你的sed不理解t(GNUsed可以,但在macos上可能不行)-或者使脚本POSIXly正确-将t替换为文字制表符
  • s//80/中的空正则表达式重新应用上次使用的正则表达式(在/…/中)
  • 使用-E选项之前扩展正则表达式

使用您展示的示例,请尝试以下awk程序。

awk '$4!="D"{sub(/^[0-9]+|^./,"1",$9);sub(/[0-9]+$|.$/,"80",$9)} 1' Input_file

如果您在Input_file中有TAB分隔值,则将BEGIN节添加到上述程序中,如下所示:

awk '
BEGIN{FS=OFS="t"}
$4!="D"{
sub(/^[0-9]+|^./,"1",$9)
sub(/[0-9]+$|.$/,"80",$9)
}
1
' Input_file

我不确定你是否真的需要对这些映射进行硬编码,但你的问题中没有其他解释,所以,假设你这样做了,那么这将在每个Unix机器的任何shell中使用任何awk:

$ cat tst.awk
BEGIN {
FS=OFS="t"
str2str[".:.:."]      = "1:.:80"
str2str[".:.:.:."]    = "1:.:.:80"
str2str[".:.:.:.:."]  = "1:.:.:80:."
for (str in str2str) {
re = str
gsub(/./,"(.|[0-9]+)",re)
re2str["^("re")$"] = str2str[str]
}
}
$4 != "D" {
for (re in re2str) {
if ($9 ~ re) {
$9 = re2str[re]
}
}
}
{ print }

$ awk -f tst.awk file
.       .       .       A       .       .       .       .       1:.:.:80
.       .       .       B       .       .       .       .       1:.:80
.       .       .       C       .       .       .       .       1:.:.:80:.
.       .       .       D       .       .       .       .       .:.:.:.
.       .       .       A       .       .       .       .       1:.:.:80
.       .       .       B       .       .       .       .       1:.:.:80
.       .       .       D       .       .       .       .       .:.:.:.
.       .       .       C       .       .       .       .       1:.:80

这是使用awk的一个可能的解决方案。

cat file | awk '{if ($4 != "D") { sub($9, "Replaced the ninth field" ); print } else { print }}''

如果第4个字段($4)不是D,将用字符串替换第9个字段($9)。

你也可以用一个正则表达式替换$9,如果你知道最后一个字段的形状足够好,像/d/./d$之类的。不确定是否也需要反向引用替换

但这可能是个开始。

cat out.tsv | awk '{if ($4 != "D") { sub($9, "Replaced the ninth field" ); print } else { print }}'
. . . A . . . . Replaced the ninth field
.   .   .   B   .   .   .   .   Replaced the ninth field
.   .   .   C   .   .   .   .   Replaced the ninth field
.   .   .   D   .   .   .   .   ./././.
.   .   .   A   .   .   .   .   Replaced the ninth field
.   .   .   B   .   .   .   .   Replaced the ninth field
.   .   .   D   .   .   .   .   ./././.
.   .   .   C   .   .   .   .   Replaced the ninth field

相关内容

  • 没有找到相关文章

最新更新