다음과 유사한 통합 분석 형식으로 변경하려는 탭으로 구분된 모델 입력 파일이 있습니다.
입력.txt
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.5
abies_grandis 2.5 0.4
larix_occidentalis 1.5 0.3
아래와 같이 한 줄에 하나씩 또 다른 승수 파일이 있습니다.
승수.txt
0.5
0.6
0.7
한 필드(wsg)에 두 번째 파일의 단일 승수를 곱하는 일련의 새 입력 파일을 생성하고 싶습니다. 이 예에서는 3개의 승수에 해당하는 3개의 새 파일이 있습니다. 출력 파일은 다음과 같습니다.
파일 1.txt(wsg*0.5)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
파일 2.txt(wsg*0.6)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
파일 3.txt(wsg*0.7)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
이는 awk와 for 루프를 사용하여 가능한 것 같지만 이 작업을 수행하는 데 필요한 수준까지 awk를 모르겠습니다. 이 문제를 어떻게 처리해야 합니까?
답변1
현재 가지고 있는 승수에 관계없이 모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.
$ ls *.txt
input.txt multipliers.txt
$ cat tst.awk
NR==FNR {
if ( pastHdr ) {
++numLines
wsg[numLines] = $NF
sub(/[[:space:]][^[:space:]]+$/,"")
rest[numLines] = $0
}
else {
hdr = hdr $0 ORS
if ( $1 == "***" ) {
pastHdr = 1
}
}
next
}
{
out = "file" FNR ".txt"
printf "%s", hdr > out
for (lineNr=1; lineNr<=numLines; lineNr++) {
print rest[lineNr], wsg[lineNr] * $0 > out
}
close(out)
}
$ awk -f tst.awk input.txt multipliers.txt
$ ls *.txt
file1.txt file2.txt file3.txt input.txt multipliers.txt
$ head file*.txt
==> file1.txt <==
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
==> file2.txt <==
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
==> file3.txt <==
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
위의 내용은 매우 유사합니다.@guest_7이 게시한 솔루션, 제가 이 글을 게시하는 이유는 다음과 같습니다:
- 많은 단일 문자 변수 이름을 사용하면 IMHO 이 크기의 스크립트는 초보자가 이해하기 어렵습니다.
- wsg 값을 삭제
NF--
하지만 NF를 줄이는 것은 정의되지 않은 동작이므로 이식성이 없습니다. - 헤더의 줄 수를 하드코딩합니다. (이것은 잘못된 것이 아닐 수도 있습니다. 텍스트를 구문 분석하여 결정하는 것이 단지 제가 선호하는 것일 뿐입니다. 그러나 실제 입력이 항상 게시된 예와 같은지 여부에 따라 틀릴 수도 있습니다. 그렇지 않은 경우에는 무엇입니까? 차이점).
답변2
곱셈은 6행 다음의 마지막 공백으로 구분된 필드에서 정확히 발생해야 한다고 가정합니다 input.txt
. 간단한 쉘 루프를 사용하십시오.
count=0
while IFS= read -r mult; do
count=$(( count + 1 ))
awk -v mult="$mult" 'NR >= 6 { $NF *= mult }; 1' <input.txt >"file$count.txt"
done <multipliers.txt
이는 루프의 각 반복에서 승수를 읽고 이를 multipliers.txt
라인 6( ) 뒤의 마지막 필드( ) 값에 적용합니다. 그런 다음 수정 여부에 관계없이 각 줄을 인쇄합니다(후행이 수행하는 작업입니다).$NF
NR >= 6
1
출력 파일 이름은 정적 접두사 file
, 카운터 및 정적 접미사로 count
생성 됩니다 .txt
.
원하는 경우 파일을 삭제할 수 있습니다 multipliers.txt
(항상 작은 상수 승수가 있는 경우).
count=0
for mult in 0.5 0.6 0.7; do
count=$(( count + 1 ))
awk -v mult="$mult" 'NR >= 6 { $NF *= mult }; 1' <input.txt >"file$count.txt"
done
답변3
input.txt 파일에는 6줄만 있으므로 awk 배열로 읽습니다.
awk '
NR==FNR {
if (NR<6) {h=h sep $0}
else {
n++; b[n]=$NF
$NF=""; a[n]=$0
}
sep = ORS
next
}
{
close(f); f = fp($1)
print h > f
for (i=1; i<=n; i++) {
print a[i] b[i]*$1 > f
}
}
function fp(m) {
sub(/[.]/, "p", m)
return "file@mult=" m ".txt"
}
' input.txt multipliers.txt
결과:
.
├── file@mult=0p5.txt
├── file@mult=0p6.txt
├── file@mult=0p7.txt
├── input.txt
└── multipliers.txt
::::::::::::::
file@mult=0p5.txt
::::::::::::::
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
::::::::::::::
file@mult=0p6.txt
::::::::::::::
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
::::::::::::::
file@mult=0p7.txt
::::::::::::::
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
답변4
j=1; while read i; do awk -v i="$i" 'NR>5{$NF=$NF*i}1' input.txt >file$j.txt\(wsg*"$i"\);j=$(($j+1)); done < multipliers.txt
산출
@praveen:~$ cat file1.txt\(wsg\*0.5\)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
===========
praveen@praveen:~$ cat file2.txt\(wsg\*0.6\)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
========
praveen@praveen:~$ cat file3.txt\(wsg\*0.7\)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
파이썬
#!/usr/bin/python
mu=open('Multipliers.txt','r')
ik=open('input.txt','r')
t=ik.readlines()
d=1
for g in mu:
er=open("file{0}.txt(wsg*{1})".format(d,g.strip()),'w')
for h in range(0,len(t),1):
if (int(h) < 5):
print t[h].strip()
er.write(t[h].strip())
er.write('\n')
else:
k=t[h].split(' ')
co=float(k[-1].strip())*float(g)
print " ".join(k[0:-1])+" "+str(co)
er.write(" ".join(k[0:-1])+" "+str(co))
er.write('\n')
d=d+1