我有两套PDB文件(这是一种无法修改的标准格式)。第一组就像:
ATOM 18 C33 Q58 d 91 -25.677 3.886 -30.044 1.00 0.00 C
ATOM 19 C34 Q58 d 91 -24.704 4.881 -29.447 1.00 0.00 C
ATOM 20 C35 Q58 d 91 -23.382 4.873 -30.182 1.00 0.00 C
ATOM 21 C8 Q58 d 91 -20.295 11.484 -33.616 1.00 0.00 C
ATOM 22 C7 Q58 d 91 -19.198 12.305 -33.381 1.00 0.00 C
ATOM 23 C3 Q58 d 91 -18.213 12.498 -34.383 1.00 0.00 C
第二个问题是:
HETATM 2686 C7 589 A 1 -19.344 12.177 -33.319 1.00 25.88 C
HETATM 2687 C8 589 A 1 -20.388 11.319 -33.511 1.00 26.31 C
HETATM 2688 C9 589 A 1 -20.364 10.691 -34.747 1.00 26.14 C
HETATM 2689 C10 589 A 1 -19.402 10.845 -35.729 1.00 26.34 C
HETATM 2690 N11 589 A 1 -21.334 11.123 -32.604 1.00 26.22 N
HETATM 2691 C12 589 A 1 -21.713 9.967 -32.081 1.00 25.65 C
每列由可变数量的空格分隔,以使其内容占据特定的位置范围。
第7-9列表示笛卡尔空间中的x,y,z坐标。对于所有第3列(原子类型)匹配,我想用文件1中的坐标替换文件2的坐标。
例如,在示例中,输出文件2将是:
HETATM 2686 C7 589 A 1 -19.198 12.305 -33.381 1.00 25.88 C
HETATM 2687 C8 589 A 1 -20.295 11.484 -33.616 1.00 26.31 C
HETATM 2688 C9 589 A 1 -20.364 10.691 -34.747 1.00 26.14 C
HETATM 2689 C10 589 A 1 -19.402 10.845 -35.729 1.00 26.34 C
HETATM 2690 N11 589 A 1 -21.334 11.123 -32.604 1.00 26.22 N
HETATM 2691 C12 589 A 1 -21.713 9.967 -32.081 1.00 25.65 C
请注意前两行(原子C7和C8)的坐标是如何变化的。
我尝试过awk,但它似乎过于依赖于分隔符,这在这个例子中并不好。第3列(原子类型)始终位于14-16位置,而3个坐标列位于32至54位。
注意:在某些情况下,某些列可能会合并。例如,在此示例中,第5列和第6列已合并(这也可能发生在第1列和第2列):
HETATM 2804 PG ANP A1001 23.808 17.953 28.350 1.00 52.23 P
我的解决方案到目前为止(缓慢但有效):
while read line ; do
atom=$(echo "$line" | cut -c13-16)
coord=$(grep -i "$atom" ${ligand}_${chain}_dock.tmp | cut -c32-54)
echo "$line" | sed -r "s/^(.{31})(.{23})/\1${coord}/" >> ${ligand}_${chain}_dock.pdb
done < ${ligand}_${chain}_ref.pdb
答案 0 :(得分:3)
我可能会选择一种愚蠢的方法来解决它:使用printf语句。但它适用于你的例子。
命令:
awk -F' *' 'NR==FNR{a[$3]=$7;b[$3]=$8;c[$3]=$9;next;}\
{if($3 in a)printf "%s %s %-3s %s %s %3s %11s %7s %7s %5s %s %11s\n",\
$1,$2,$3,$4,$5,$6,a[$3],b[$3],c[$3],$10,$11,$12; else print $0}' file1 file2
用你的例子测试:
kent$ awk -F' *' 'NR==FNR{a[$3]=$7;b[$3]=$8;c[$3]=$9;next;}
{if($3 in a)printf "%s %s %-3s %s %s %3s %11s %7s %7s %5s %s %11s\n",
$1,$2,$3,$4,$5,$6,a[$3],b[$3],c[$3],$10,$11,$12; else print $0}' file1 file2
HETATM 2686 C7 589 A 1 -19.198 12.305 -33.381 1.00 25.88 C
HETATM 2687 C8 589 A 1 -20.295 11.484 -33.616 1.00 26.31 C
HETATM 2688 C9 589 A 1 -20.364 10.691 -34.747 1.00 26.14 C
HETATM 2689 C10 589 A 1 -19.402 10.845 -35.729 1.00 26.34 C
HETATM 2690 N11 589 A 1 -21.334 11.123 -32.604 1.00 26.22 N
HETATM 2691 C12 589 A 1 -21.713 9.967 -32.081 1.00 25.65 C
答案 1 :(得分:1)
我猜测了正确的字段宽度,但是如果它们被正确调整就应该有效。
#!/usr/bin/env bash
file1="$1"
file2="$2"
fw=(7 6 4 4 4 6 9 7 9 5 16 4)
while IFS= read -r -a f2_line ; do
let pos=0
f2_fields=()
for width in "${fw[@]}" ; do
f2_fields=("${f2_fields[@]}" "${f2_line:${pos}:${width}}")
let pos+=width
done
printf '%s' "${f2_fields[@]:0:6}"
orig=1
while IFS= read -r -a f1_line ; do
let pos=0
f1_fields=()
for width in "${fw[@]}" ; do
f1_fields=("${f1_fields[@]}" "${f1_line:${pos}:${width}}")
let pos+=width
done
if [ "${f1_fields[2]}" = "${f2_fields[2]}" ] ; then
orig=
printf '%s' "${f1_fields[@]:6:3}"
break
fi
done < "$file1"
if [ ! -z "$orig" ] ; then
printf '%s' "${f2_fields[@]:6:3}"
fi
printf '%s' "${f2_fields[@]:9}"
printf '\n'
done < "$file2"
当然,效率不高。
编辑:糟糕,不得不在第14行上获得s / 5/6 /。立即行动。
答案 2 :(得分:0)
这也会奏效。我们不是打印每一列,而是将OFS变量设置为“\ t”。
UPDATE:在OFS变量的标签旁边添加了更多空格。这为您的输出提供了足够的间距。
[jaypal:~/Temp] awk -v OFS="\t " 'NR==FNR{a[$3]=$7;b[$3]=$8;c[$3]=$9;next} ($3 in a) {$7=a[$3];$8=b[$3];$9=c[$3];print $0;next} {$1=$1}1' file1 file2
HETATM 2686 C7 589 A 1 -19.198 12.305 -33.381 1.00 25.88 C
HETATM 2687 C8 589 A 1 -20.295 11.484 -33.616 1.00 26.31 C
HETATM 2688 C9 589 A 1 -20.364 10.691 -34.747 1.00 26.14 C
HETATM 2689 C10 589 A 1 -19.402 10.845 -35.729 1.00 26.34 C
HETATM 2690 N11 589 A 1 -21.334 11.123 -32.604 1.00 26.22 N
HETATM 2691 C12 589 A 1 -21.713 9.967 -32.081 1.00 25.65 C