후속작입니다유닉스: 한 파일의 전체 열을 다른 파일의 단일 값으로 바꿉니다.
파일(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]
입력 줄 끝에 구분 문자(공백)가 됩니다.
다음은 더 읽기 쉬운 형식의 한 줄의 코드입니다.
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