Думаю, это подойдет для GNUsed
:
sed -E 's/^([A-Z]+\.)[[:blank:]]([A-Z]+\.)/\1\2/' file
Использование любого awk в любой оболочке на каждой машине Unix, независимо от того, сколько у вас множителей:
$ 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 опубликовал , я разместил его, потому что их:
NF--
для удаления значения wsg, но уменьшение NF является поведением undefined и, следовательно, -не переносимым, и Предполагая, что умножение должно выполняться точно с последними пробелами, -разделенными полями в строках 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
на каждой итерации цикла, а затем применяет его к значению последнего поля($NF
)в строках 6 и далее(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
Вот один из способов (GNU awk):
gawk '{
if(NR==FNR){
mlt[$1]
}
else{
oldVal=$3
for(m in mlt){
outFile="outfile_"m".txt";
if(a){ $3 = oldVal * m}
if($4 == "wsg"){ a=1 }
print $0 > outFile
}
}
}' multipliers.txt input.txt
Это создает следующие файлы:
внешний файл _0.5.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
внешний файл _0.6.txt:
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name 0 wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
внешний файл _0.7.txt:
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name 0 wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
if(NR==FNR) { mlt[$1] }
:если мы читаем первый файл, сохраняем значение в массиве mlt
. else {... }
:если мы не читаем первый файл. oldVal=$3
:сохранить исходное значение третьего поля, чтобы мы могли позже умножить его. Обратите внимание, что это также сохраняет значения строк, которые мы не хотим умножать, или даже тех, у которых нет третьего поля, но это не имеет значения, потому что мы не будем использовать его для этих строк. for(m in mlt){... }
:перебираем массив mlt
(множители ), сохраняя каждый множитель как m
. outFile="outfile_"m".txt";
:установите имя выходного файла как outfile_
, затем текущий множитель m
, а затем расширение .txt
, поскольку вы, похоже, используете их. if(a){ $3 = oldVal * m}
:если установлена переменная a
, умножить третье поле на m
. if($4 == "wsg"){ a=1 }
:, если 4-е поле этой строки — wsg
, установите a
на 1
. Это используется на шаге, упомянутом выше, чтобы узнать, должны ли мы умножать. print $0 > outFile
:вывести текущую строку в выходной файл. Текущая строка уже была изменена путем умножения ее 3-го поля. Судя по всему, не -GNU awk требуют, чтобы вы закрывали открытые файлы, и мне также сказали, что даже GNU awk может работать медленнее, если вы этого не сделаете. Если вы столкнулись с такой проблемой, вы можете попробовать эту версию, которая закрывает файл после каждого чтения. Если вы используете это, поскольку оно будет добавлять к выходному файлу , убедитесь, что вы удалили все уже существующие выходные файлы перед запуском.
awk '{
if(NR==FNR){
mlt[$1]
}
else{
oldVal=$3
for(m in mlt){
outFile="outfile_"m".txt";
if(a){ $3 = oldVal * m}
if($4 == "wsg"){ a=1 }
print $0 >> outFile
close(outFile)
}
}
}' multipliers.txt input.txt
Я протестировал оба приведенных выше решения, используя файл множителя с 1001 различным значением, и второе, закрывающее файл, было на самом деле медленнее (0m0.131s ), чем первое, которое не закрывалось (0m0.107s ).Однако это может быть связано с тем, что я повторно открываю и закрываю файл после каждой записи, что вообще не является эффективным подходом. Для контекста решение Эда Мортона , которое также аккуратно закрывает файлы, но достаточно умно, чтобы не делать этого после каждой записи, заняло всего 0 м 0,058 с на одних и тех же тестовых данных, так что быстрее, чем оба моих решения.
Мы читаем файл input.txt в массив awk, так как он состоит всего из 6 строк.
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
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
Зачем использовать удобный интерпретируемый язык оболочки или Python, если все можно сделать на C?? ;)
gcc -o gomult gomult.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void procfile(char *inputfile,double m);
int main(int argc,char *argv[])
{
char inputfile[256],multfile[256];
FILE *in,*mult;
char buf[256];
if (argc<3)
{
printf("usage: gomult <infile> <multfile>\n");
return(10);
}
strncpy(inputfile,argv[1],255);
strncpy(multfile,argv[2],255);
in=fopen(inputfile,"r");
if (in==NULL)
{
printf("Cannot open input file %s for input.\n",inputfile);
return(20);
}
fclose(in);
mult=fopen(multfile,"r");
if (mult==NULL)
{
printf("Cannot open multiplier file %s for input.\n",multfile);
return(30);
}
/* Get next line from multiplier file */
while (fgets(buf,255,mult)!=NULL)
{
int na;
double m;
/* If it's a number, process input file with it */
na=sscanf(buf,"%lf",&m);
if (na==1)
procfile(inputfile,m);
}
fclose(mult);
return(0);
}
static void procfile(char *inputfile,double m)
{
FILE *in;
FILE *out;
char outfile[256];
char buf[256];
static int count=1;
int cc;
in=fopen(inputfile,"r");
if (in==NULL)
{
printf("Could not open input file %s for input(!).\n",inputfile);
exit(10);
}
sprintf(outfile,"file%d.txt",count);
count++;
out=fopen(outfile,"w");
if (out==NULL)
{
printf("Could not open output file %s for output.\n",outfile);
return;
}
/* Fixed line count */
cc=0;
/* Get next line from input file */
while (fgets(buf,255,in)!=NULL)
{
int na5,na;
char name[256];
double n1,n2;
/* If line has string and two numbers, fix it, otherwise pass it through */
/* na5 checks line for 5 numbers--need to pass that one through */
na5=sscanf(buf,"%*f %*f %*f %lf %lf",&n1,&n2);
na=sscanf(buf,"%s %lf %lf",name,&n1,&n2);
if (na5==2 || na!=3)
fprintf(out,"%s",buf);
else
{
fprintf(out,"%s\t%g\t%g\n",name,n1,n2*m);
cc++;
}
}
fclose(out);
fclose(in);
printf("File %s written with %d changed lines.\n",outfile,cc);
}