フォローアップです。Unix:あるファイルの列全体を別のファイルの単一の値に置き換えます。
ファイル(file1)の列を別のファイル(file2)の特定の値に置き換えようとしています。
file1の構造は次のとおりです。
HETATM 8 P FAD B 600 98.424 46.244 76.016 1.00 18.65
HETATM 9 O1P FAD B 600 98.634 44.801 75.700 1.00 17.69 O
HETATM 10 O2P FAD B 600 98.010 46.640 77.387 1.00 15.59 O
HETATM 11 H5B1 FAD B 600 96.970 48.950 72.795 1.00 -1.00 H
この構造を維持する必要があります。
file2の構造は次のとおりです。
1 27, -81.883, 4.0
5 48, -67.737, 20.0
1 55, -72.923, 4.0
4 27, -62.64, 16.0
私はawkが「誤動作」し、私のpdbファイルの形式を失ったことに気づきました。これは代わりに次のことを意味します。
HETATM 1 PA FAD B 600 95.987 47.188 74.293 1.00 -73.248
わかりました。
HETATM 1 PA FAD B 600 95.887 47.194 74.387 1.00 -73.248
私は試した:
file1="./Min1_1.traj_COP1A_.27.pdb"
file2="./COP1A_report1"
value="$(awk -F, 'NR==1{print $2;exit}' $file2)"
#option 1: replaces the column I want but messes up the format
awk -F ' ' '{$11 = v} 1' v="$value" $file1 >TEST1
#option 2: keeps the format but adds the value at the end only
awk -F ' ', '{$2 = v} 1' v="$value" $file1 >TEST2
awk -F, '{$11 = v} 1' v="$value" $file1 >TEST3
私はこれがpdbファイルのすべての列に同じ区切り文字を持たず、awkが私が望む方法で処理しないためだと思います。
この問題を解決するためにawkを「飼いならす」方法や使用する他のコマンドに関するアイデアはありますか?
答え1
空白ではなく正規表現を使用[^[:blank:]]
し、最初の11
一致を置き換えます。
awk '{print gensub (/[^[:blank:]]+/, v, 11)}' v="$value" infile
sed
同じ
sed "s/[^[:blank:]]\{1,\}/${value}/11" infile
別の方法は、ファイルに固定長フィールドがあり、各フィールドの「位置」を知っている場合(例ファイルに空白だけがあると仮定すると、11番目のフィールドは4文字を占め、各行は57番目から60番目になります。 )
awk '{print substr($0,1,56) v substr($0,61)}' v=$value file
または
sed -E "s/^(.{56}).{4}(.*)$/\1${value}\2/" infile
答え2
GAWK 4では、文字列(または行全体)を明示的に分割し、出力のために分割結果(フィールドと区切り文字)を繰り返してフィールド区切り文字を保存できます。
この例では、FPAT
フィールド構造を指定する正規表現を使用していますが、フィールド区切り文字を指定するか、単一のスペースを含む正規表現をpatsplit()
使用することもできます。FS
[ \t\n]+
split()
gawk "v=$value" '{n = patsplit($0, arr, FPAT, seps); arr[11] = v; for (i = 0; i <= n; i++) {printf "%s%s", a[i], seps[i]}; print ""}'
これはa[0]
常に空で、前のseps[0]
区切り文字を含み、seps[n]
入力行の末尾に区切り文字(空白)になります。
以下は、より読みやすい形式の1行のコードです。
gawk "v=$value" '
{
n = patsplit($0, arr, FPAT, seps);
arr[11] = v;
for (i = 0; i <= n; i++) {
printf "%s%s", a[i], seps[i]
};
print ""
}'
答え3
sed
あなたの仕事に使用したい:
file1="./Min1_1.traj_COP1A_.27.pdb"
file2="./COP1A_report1"
IFS=',' read -r a value b <"$file2"
#for second field:
sed "s/.[0-9]\b/$value/" "$file1" > TEST1
#for 11th field:
sed "s/\S.\.[0-9]\{2\}\b/$value/" "$file1" > TEST1