Арифметика между двумя файлами, создающая серию новых файлов

Думаю, это подойдет для GNUsed:

sed -E 's/^([A-Z]+\.)[[:blank:]]([A-Z]+\.)/\1\2/' file
1
12.02.2021, 21:49
6 ответов

Использование любого 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 опубликовал , я разместил его, потому что их:

  1. Используется много односимвольных имен переменных, которые, ИМХО, делают скрипт такого размера намного сложнее для понимания новичками,
  2. Используйте NF--для удаления значения wsg, но уменьшение NF является поведением undefined и, следовательно, -не переносимым, и
  3. Жесткий -кодирует количество строк в заголовке (, что может быть правильным, просто я предпочитаю определять это на основе анализа текста -, но это также может быть неправильным в зависимости от того, является ли ввод всегда выглядит как в опубликованном примере, а если нет, то чем он отличается ).
3
18.03.2021, 22:30

Предполагая, что умножение должно выполняться точно с последними пробелами, -разделенными полями в строках 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
1
18.03.2021, 22:30

Вот один из способов (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 с на одних и тех же тестовых данных, так что быстрее, чем оба моих решения.

1
18.03.2021, 22:30

Мы читаем файл 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
1
18.03.2021, 22:30
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        
0
18.03.2021, 22:30

Зачем использовать удобный интерпретируемый язык оболочки или 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);
    }
0
18.03.2021, 22:30

Теги

Похожие вопросы