BASH - 使用 for 循环和 If 语句将第 2 列中的信息更改为 2
BASH - Change information in columns 2 by 2 using for loop and If statements
我有以下制表符分隔的文件:
A1 A1 0 0 1 1 0 0 0 0 2 2 1 2
A2 A2 0 0 1 1 1 1 1 1 0 0 1 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 1 2
想法是修改第 7 列(包括)和末尾之间的信息,对于每一行,如果第 7 列和第 8 列:
等于“0 0”:不修改
等于“1 1”:不修改
等于“1 2”或“2 1”:改为“2 2”
等于“2 2”:不修改
以下各列(第 9 和 10,然后是 11 和 12、13 和 14,等等)也是如此。
我开始使用以下命令提取我想要处理的列:
awk '{for (i = 7; i <= NF; i++) printf $i " "; print ""}' test.ped > tmp_test.txt
然后我想在 If 语句中使用 for 循环,一般格式为:
for i between 7 and the end (for (i = 7; i <= NF)):
if i and i+1 == “1 2”:
replace by “2 2”
elif i and i+1 == “2 1”:
replace by “2 2”
else
pass
i=i+2 (increase i to do the same for the next double columns)
但是我被困在这里了。一般格式是否合乎逻辑,或者是否有更快的方法来做同样的事情?我正朝着正确的方向前进吗?
预期输出(在合并初始文件的前 6 列和我子集化和修改的列之后)是:
A1 A1 0 0 1 1 0 0 0 0 2 2 2 2
A2 A2 0 0 1 1 1 1 1 1 0 0 2 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 2 2
感谢您的帮助!
$ awk '{=;for(i=7;i<=NF;i+=2) if($i""$(i+1)=="1""2" || $i""$(i+1)=="2""1") {$i=2;$(i+1)=2} print}' test
A1 A1 0 0 1 1 0 0 0 0 2 2 2 2
A2 A2 0 0 1 1 1 1 1 1 0 0 2 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 2 2
.
{
= # break the record (for even output)
for(i=7;i<=NF;i+=2) # the loop increase by 2s
if($i""$(i+1)=="1""2" || $i""$(i+1)=="2""1") {
$i=2;$(i+1)=2 # reset col values if 1,2 OR 2,1
}
print # print record, changed or not
}
Awk
是你的朋友。
awk -v FS='\t' -v OFS='\t' '{for(i=7;i<=NF;i++) \
{if($i ~ /^[ 2]*[1]{1}[ 2]*$/){$i="2 2"}}}1' file
应该做。
从您的问题来看,以下几对列似乎是 space 分开的(第 7 和第 8)、(第 9 和 10)、(第 11 和第 12)、(第 13 和第 14)。其他的是制表符分隔的。如果是这样的话,你可以不用循环就可以做到。
awk '{sub("1 2","2 2",[=10=]);sub("2 1","2 2",[=10=]); print;}' <filename>
听起来你只需要:
$ awk '{gsub(/1 2|2 1/,"2 2")}1' file
A1 A1 0 0 1 1 0 0 0 0 2 2 2 2
A2 A2 0 0 1 1 1 1 1 1 0 0 2 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 2 2
但是您的示例 input/output 确实无法帮助证明您的文字描述的内容,而且我认为您的字段并不像您所说的那样全部采用制表符分隔,所以这只是猜测。
我有以下制表符分隔的文件:
A1 A1 0 0 1 1 0 0 0 0 2 2 1 2
A2 A2 0 0 1 1 1 1 1 1 0 0 1 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 1 2
想法是修改第 7 列(包括)和末尾之间的信息,对于每一行,如果第 7 列和第 8 列:
等于“0 0”:不修改
等于“1 1”:不修改
等于“1 2”或“2 1”:改为“2 2”
等于“2 2”:不修改
以下各列(第 9 和 10,然后是 11 和 12、13 和 14,等等)也是如此。
我开始使用以下命令提取我想要处理的列:
awk '{for (i = 7; i <= NF; i++) printf $i " "; print ""}' test.ped > tmp_test.txt
然后我想在 If 语句中使用 for 循环,一般格式为:
for i between 7 and the end (for (i = 7; i <= NF)):
if i and i+1 == “1 2”:
replace by “2 2”
elif i and i+1 == “2 1”:
replace by “2 2”
else
pass
i=i+2 (increase i to do the same for the next double columns)
但是我被困在这里了。一般格式是否合乎逻辑,或者是否有更快的方法来做同样的事情?我正朝着正确的方向前进吗?
预期输出(在合并初始文件的前 6 列和我子集化和修改的列之后)是:
A1 A1 0 0 1 1 0 0 0 0 2 2 2 2
A2 A2 0 0 1 1 1 1 1 1 0 0 2 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 2 2
感谢您的帮助!
$ awk '{=;for(i=7;i<=NF;i+=2) if($i""$(i+1)=="1""2" || $i""$(i+1)=="2""1") {$i=2;$(i+1)=2} print}' test
A1 A1 0 0 1 1 0 0 0 0 2 2 2 2
A2 A2 0 0 1 1 1 1 1 1 0 0 2 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 2 2
.
{
= # break the record (for even output)
for(i=7;i<=NF;i+=2) # the loop increase by 2s
if($i""$(i+1)=="1""2" || $i""$(i+1)=="2""1") {
$i=2;$(i+1)=2 # reset col values if 1,2 OR 2,1
}
print # print record, changed or not
}
Awk
是你的朋友。
awk -v FS='\t' -v OFS='\t' '{for(i=7;i<=NF;i++) \
{if($i ~ /^[ 2]*[1]{1}[ 2]*$/){$i="2 2"}}}1' file
应该做。
从您的问题来看,以下几对列似乎是 space 分开的(第 7 和第 8)、(第 9 和 10)、(第 11 和第 12)、(第 13 和第 14)。其他的是制表符分隔的。如果是这样的话,你可以不用循环就可以做到。
awk '{sub("1 2","2 2",[=10=]);sub("2 1","2 2",[=10=]); print;}' <filename>
听起来你只需要:
$ awk '{gsub(/1 2|2 1/,"2 2")}1' file
A1 A1 0 0 1 1 0 0 0 0 2 2 2 2
A2 A2 0 0 1 1 1 1 1 1 0 0 2 2
A3 A3 0 0 1 2 1 1 1 1 0 0 2 2
A4 A4 0 0 1 1 1 1 0 0 0 0 2 2
但是您的示例 input/output 确实无法帮助证明您的文字描述的内容,而且我认为您的字段并不像您所说的那样全部采用制表符分隔,所以这只是猜测。