다른 시뮬레이션을 실행하기 위한 입력으로 준비하기 위해 다시 포맷해야 하는 시뮬레이션 파일에서 데이터를 추출하고 싶습니다. 타겟 데이터는 최적화된 화학물질입니다.z 행렬. 링크의 예와 유일한 차이점은 숫자가 z 행렬 아래에 변수로 저장된다는 것입니다.
제가 작업 중인 파일은 수천에서 수십만 개의 행에 걸쳐 있고 대상 데이터와 매우 유사한 다른 중간 z 행렬을 포함할 수 있습니다. 하지만 필요한 데이터 뒤에는 고유한 선행 행과 행이 있으므로 이 두 행 사이의 데이터는 비교적 쉽게 추출할 수 있습니다. 예는 다음과 같습니다.
Final structure in terms of initial Z-matrix:
Cl
C,1,B1
C,2,B2,1,A2
H,2,B3,1,A3,3,D3,0
H,2,B4,1,A4,3,D4,0
C,3,B5,2,A5,1,D5,0
C,6,B6,3,A6,2,D6,0
C,7,B7,6,A7,3,D7,0
H,3,B8,2,A8,1,D8,0
H,3,B9,2,A9,1,D9,0
H,7,B10,6,A10,3,D10,0
H,7,B11,6,A11,3,D11,0
H,8,B12,7,A12,6,D12,0
H,8,B13,7,A13,6,D13,0
H,8,B14,7,A14,6,D14,0
O,6,B15,3,A15,2,D15,0
Variables:
B1=1.81746475
B2=1.52136867
A2=110.80057513
B3=1.0898967
A3=106.92512231
D3=-121.94499481
B4=1.08989406
A4=106.92581701
D4=121.94497834
B5=1.52808963
A5=111.92359259
D5=179.99770382
B6=1.523193
A6=116.49970868
D6=179.97424974
B7=1.52739317
A7=113.56269053
D7=179.98802896
B8=1.09816794
A8=110.50682514
D8=58.2854688
B9=1.09816384
A9=110.50888758
D9=-58.28349045
B10=1.10022643
A10=107.84652382
D10=56.40290615
B11=1.10022793
A11=107.84460667
D11=-56.42958848
B12=1.09398015
A12=110.97242167
D12=-59.62466169
B13=1.09473047
A13=110.53459142
D13=179.99742235
B14=1.09397826
A14=110.9720435
D14=59.61905862
B15=1.21736254
A15=121.22780588
D15=-0.02140167
1\1\GINC-C0959\FOpt\RB3LYP\6-31G(d)\C5H9Cl1O1\SKYLERS\10-Sep-2013\0\\#
또한 이 데이터의 형식을 다시 지정하고 첫 번째 섹션의 쉼표를 공백으로 바꿔야 하며 변수는 왼쪽으로 들여쓰기된 문자와 오른쪽으로 들여쓰기된 숫자로 이루어져야 합니다. 또한 입력 파일 이름을 기반으로 이 데이터를 새 파일에 쓰도록 이 스크립트를 설정하고 싶습니다.
내 목표는 다음과 같이 요약됩니다.
- abc.out 파일을 엽니다.
- "초기 Z 행렬의 최종 구조:" 이후 읽기를 시작합니다.
- Z 행렬의 형식을 다시 지정합니다.
- 변수 형식 변경
- abc.cm 파일에 쓰기
지금까지 내가 사용을 고려하고 있는 awk의 부분은 다음과 같습니다.
{FS=","};{OFS=" "};{print $0}
{FS="="};{printf "%-4s%13.8f", $1, $2}
내가 아직 파악하지 못한 것은 다음과 같습니다.
- 입력 파일 이름을 기반으로 파일을 작성하는 방법은 무엇입니까?
- 첫 번째 줄과 마지막 줄 사이의 내용만 읽으려면 어떻게 해야 합니까?
- "Variable:"에서 어떻게 분할해야 합니까?
답변1
기본적으로 작은 상태 머신을 작성하게 됩니다.
awk '
BEGIN {
FS = ","
OFS = " " # this is the default
}
# create the output file name
# on the first line of the input, the FILENAME variable will be populated
FNR == 1 {
f = FILENAME
sub(/\.out/,".cm",f)
}
# I assume this is the magic closing line.
# All the backslashes and regular-expression metacharacters
# have to be backslash-escaped
/1\\1\\GINC-C0959\\FOpt\\RB3LYP\\6-31G\(d\)\\C5H9Cl1O1\\SKYLERS\\10-Sep-2013\\0\\\\#/ {
print "got end"
exit
}
started && /Variables:/ {
variables = 1
FS = "="
next
}
started && !variables {
# do stuff with comma-separated lines
# rewrite the file using space as separator
# this looks weird, but it forces awk to re-write the line using OFS
$1 = $1
print > f
}
started && variables {
# do stuff with "="-separated lines
# the FS here is "=", so there should be 2 fields.
printf "%-5s %15.8f\n", $1, $2 > f
}
!started && /Final structure in terms of initial Z-matrix/ {
started = 1
}
' abc.out
입력 내용에 따라 "abc.cm" 파일이 생성됩니다.
Cl
C 1 B1
C 2 B2 1 A2
H 2 B3 1 A3 3 D3 0
H 2 B4 1 A4 3 D4 0
C 3 B5 2 A5 1 D5 0
C 6 B6 3 A6 2 D6 0
C 7 B7 6 A7 3 D7 0
H 3 B8 2 A8 1 D8 0
H 3 B9 2 A9 1 D9 0
H 7 B10 6 A10 3 D10 0
H 7 B11 6 A11 3 D11 0
H 8 B12 7 A12 6 D12 0
H 8 B13 7 A13 6 D13 0
H 8 B14 7 A14 6 D14 0
O 6 B15 3 A15 2 D15 0
B1 1.81746475
B2 1.52136867
A2 110.80057513
B3 1.08989670
A3 106.92512231
D3 -121.94499481
B4 1.08989406
A4 106.92581701
D4 121.94497834
B5 1.52808963
A5 111.92359259
D5 179.99770382
B6 1.52319300
A6 116.49970868
D6 179.97424974
B7 1.52739317
A7 113.56269053
D7 179.98802896
B8 1.09816794
A8 110.50682514
D8 58.28546880
B9 1.09816384
A9 110.50888758
D9 -58.28349045
B10 1.10022643
A10 107.84652382
D10 56.40290615
B11 1.10022793
A11 107.84460667
D11 -56.42958848
B12 1.09398015
A12 110.97242167
D12 -59.62466169
B13 1.09473047
A13 110.53459142
D13 179.99742235
B14 1.09397826
A14 110.97204350
D14 59.61905862
B15 1.21736254
A15 121.22780588
D15 -0.02140167
답변2
다음은 Python 스크립트입니다.
#!/usr/bin/env python
from __future__ import print_function
import sys
StartStr = 'Final structure in terms of initial Z-matrix'
StopStr = '1\\1\\GINC-C0959\\FOpt\\RB3LYP\\6-31G(d)\\C5H9Cl1O1\\SKYLERS\\10-Sep-2013\\0\\\\#'
def main():
v,start = 0,0
for line in InputFile:
line = line.strip()
if StartStr in line: start = 1; continue
if StopStr in line: break
if start:
if v: print('\t'.join(line.split('=')))
else:
if "Variables" in line: v = 1; print(); continue
print(' '.join(line.split(',')))
if __name__ == '__main__':
if len(sys.argv) != 2:
print( "\nUsage:\t",sys.argv[0],'<InputFile>\n',file=sys.stderr )
else:
try:
## create the output file name
outputFile=sys.argv[1].split('.')[0],".cm"
o = ''.join(outputFile)
print("Your Final Output Saved in:- ",o)
with open(sys.argv[1],'r') as InputFile:
sys.stdout = open(o,'w')
main()
except:
print("Problem with Opening file",sys.argv[1],file=sys.stderr)
답변3
이는 Perl을 사용하여 수행할 수도 있습니다.트리거 연산자. 셸에 다음을 입력합니다.
INFILE="abc.out" #Quotes only necessary ...
OUTFILE="${INFILE%.*}".cm # ... if you have spaces in the file names
perl -nle '
if(m{\QFinal structure in terms of initial Z-matrix:\E} ..
m{\Q1\1\GINC-C0959\FOpt\RB3LYP\6-31G(d)\C5H9Cl1O1\SKYLERS\10-Sep-2013\0\\#\E}){
(s/,/ /g or !/=|:/) and print;
/([^=]+)=([^=]+)/ and printf "%-4s %13.8f\n", $1,$2
}
' "$INFILE" > "$OUTFILE"
답변4
이것은 awk의 또 다른 버전입니다.
awk -f- <<\EOF data
FNR==1 { f = FILENAME".new" }
/Final structure in terms of initial Z-matrix:/ {
FS=","
while ( getline > 0 ) {
if ( $0 ~ /Variables:/ ) break
$1=$1
print $0 > f
}
FS="="
while ( getline > 0 ) {
if( NF == 2 ) {
printf "%-5s%15.8f\n", $1, $2 > f
} else {
break
}
}
}
EOF