в поисках лучших решений awk или perl: избегая xargs и т.п. - PullRequest
4 голосов
/ 13 ноября 2011

Мне пришлось проанализировать файлы, в которых перечислены собственные векторы квадратной матричной матрицы в формате файла из семи столбцов, в квадратную матрицу, в которой каждый собственный вектор является столбцом матрицы

Eigenvector file: COVAR
   72   72
   42.27674   53.43516   43.10335   43.43889   53.15094   43.77146   43.17536
   52.49170   45.07565   42.10424   52.75460   45.74721   41.66882   52.21836
   47.00361   40.21403   51.86627   47.05245   39.75512   50.92583   47.83411
   38.36019   50.61541   48.00747   37.56547   51.66199   48.72199   36.29018
   51.70312   48.54869   35.35773   52.59045   49.19493   34.14085   51.90543
   49.78376   33.43961   52.55997   50.66576   32.13812   52.14743   51.17284
   31.02647   52.41422   50.19470   30.02426   51.60068   50.14591   28.86206
   51.70417   49.28895   27.52769   51.49614   49.94867   27.52460   50.99136
   51.12215   26.37751   50.74786   51.93507   25.23025   50.04549   51.26765
   25.46212   49.27591   50.30035   24.47349   48.61017   49.51955   23.64720
   49.41136   48.60875
 ****
    1     3.28044
    0.06504   -0.20409   -0.08035    0.04603   -0.02034   -0.02343    0.03885
    0.14025    0.01970   -0.00569    0.11391   -0.05271   -0.00874    0.25005
   -0.02425    0.03969    0.13327    0.01054    0.09958    0.20857    0.08647
    0.13883    0.12003    0.12859    0.05634    0.06415    0.02570    0.07466
   -0.06541    0.04636    0.01246   -0.13691   -0.04270    0.03791   -0.15341
   -0.02595   -0.01027   -0.15604   -0.08393   -0.00526   -0.16938   -0.09027
    0.01573   -0.25999   -0.09350    0.01121   -0.24367   -0.01033    0.03059
   -0.31268   -0.00040    0.02074   -0.17927   -0.01689   -0.02183   -0.03912
   -0.01481   -0.03982    0.10507   -0.03446   -0.06896    0.20946   -0.00450
   -0.17669    0.17617    0.08755   -0.21143    0.25313    0.12818   -0.13896
    0.16625    0.06539
 ****
    2     1.17147
    0.05028    0.24209    0.07571    0.07015    0.26226    0.10552    0.09788
    0.15535    0.10020    0.06248    0.07167    0.09337    0.06555   -0.05258
    0.07777    0.05163   -0.08617   -0.01580    0.05087   -0.17374   -0.06483
    0.03157   -0.18854   -0.12423    0.02388   -0.15753   -0.07304    0.00221
   -0.12406   -0.11678   -0.00030   -0.07568   -0.07783   -0.00225   -0.10201
   -0.09521    0.00373   -0.10066   -0.06755   -0.00386   -0.10808   -0.08343
   -0.01420   -0.03899   -0.11123   -0.06186   -0.02282   -0.11633   -0.07596
    0.03656   -0.14599   -0.07542    0.13621   -0.11299   -0.07350    0.22728
   -0.02254   -0.07473    0.32577    0.01167   -0.09106    0.17148    0.10912
   -0.01607    0.00303    0.19984   -0.01223   -0.16824    0.28827   -0.00879
   -0.23259    0.16630
 ****
   3 et cetera ....

Мне удалось решить мою проблему, как я мог, с большим количеством каналов ... это фрагмент моего сценария, который также извлекает собственные значения (число рядом с натуральными числами под ****)

local dimensions=$(awk 'NR==2 {print$1}'  ${ptraj_eigvect[$k]}) #in the second line of the file it is written the dimension of the rotation matrix
#Ptraj produces a file in seven columns format
#                        ||
#                        \/
if [[ $((${dimensions} % 7 )) == 0  ]]
then
       local -i n_rows_eigvect_ptraj=$(( ${dimensions} / 7 ))
else
       local -i n_rows_eigvect_ptraj=$(( (${dimensions} / 7) + 1 ))
fi
#        headers          matrix         ****
#          ||   |||||||||||||||||||||||  ||
#          \/   \/\/\/\/\/\/\//\/\/\/\/  \/
awk 'NR>'$(( 2 + ${n_rows_eigvect_ptraj} + 1 ))' && NR%'$(( 2 + ${n_rows_eigvect_ptraj} ))'==2' ${ptraj_eigvect[$k]}  >${eigval_file}

awk 'NR>'$(( 2 + ${n_rows_eigvect_ptraj} + 2 ))' && NR%'$(( 2 + ${n_rows_eigvect_ptraj} ))'!=2 && NR%'$(( 2 + ${n_rows_eigvect_ptraj} ))'!=1' ${ptraj_eigvect[$k]} | xargs printf "%s\n" | awk '($0=$NF x)&&ORS=NR%'${dimensions}'?FS:RS' | awk -f ${script_PA}/transpose.awk >${rotmatr_file}

 if [[ $(wc -l <${rotmatr_file}) != ${dimensions}  ]] || [[ $(wc -w <${rotmatr_file}) != $(( ${dimensions} * ${dimensions} ))  ]]
 then
       echo 'ERROR!!!' 
       exit 1
  fi

файл transpose.awk здесь

Я редактирую по запросу

мой сценарий, полученный в виде квадратной матрицы 72 x 72, здесь я пишу только первые 2 столбца. Вы можете видеть, что числа соответствуют номерам после 1 3.28044 и 2 1.17147

0.06504 0.05028
-0.20409 0.24209
-0.08035 0.07571
0.04603 0.07015
-0.02034 0.26226
-0.02343 0.10552
0.03885 0.09788
0.14025 0.15535
0.01970 0.10020
-0.00569 0.06248
0.11391 0.07167
-0.05271 0.09337
-0.00874 0.06555
0.25005 -0.05258
-0.02425 0.07777
0.03969 0.05163
0.13327 -0.08617
0.01054 -0.01580
0.09958 0.05087
0.20857 -0.17374
0.08647 -0.06483
0.13883 0.03157
0.12003 -0.18854
0.12859 -0.12423
0.05634 0.02388
0.06415 -0.15753
0.02570 -0.07304
0.07466 0.00221
-0.06541 -0.12406
0.04636 -0.11678
0.01246 -0.00030
-0.13691 -0.07568
-0.04270 -0.07783
0.03791 -0.00225
-0.15341 -0.10201
-0.02595 -0.09521
-0.01027 0.00373
-0.15604 -0.10066
-0.08393 -0.06755
-0.00526 -0.00386
-0.16938 -0.10808
-0.09027 -0.08343
0.01573 -0.01420
-0.25999 -0.03899
-0.09350 -0.11123
0.01121 -0.06186
-0.24367 -0.02282
-0.01033 -0.11633
0.03059 -0.07596
-0.31268 0.03656
-0.00040 -0.14599
0.02074 -0.07542
-0.17927 0.13621
-0.01689 -0.11299
-0.02183 -0.07350
-0.03912 0.22728
-0.01481 -0.02254
-0.03982 -0.07473
0.10507 0.32577
-0.03446 0.01167
-0.06896 -0.09106
0.20946 0.17148
-0.00450 0.10912
-0.17669 -0.01607
0.17617 0.00303
0.08755 0.19984
-0.21143 -0.01223
0.25313 -0.16824
0.12818 0.28827
-0.13896 -0.00879
0.16625 -0.23259
0.06539 0.16630

Поскольку я пытаюсь изучать awk и, возможно, в будущем perl, прошу вас научить меня, как написать скрипт на awk или perl, который выполняет ту же задачу

Большое спасибо за внимание

Ответы [ 5 ]

2 голосов
/ 13 ноября 2011

Работал над этим некоторое время, ничего хорошего не придумал, но приведенный ниже код, похоже, работает, несмотря на то, что он довольно неуклюжий.Предполагается, что ваши данные полностью единообразны и не заботятся о заголовках.

Положительной стороной является то, что если вы измените <DATA> на <>, он будет работать с вашим файлом данных с:

> script.pl input > output

Если предполагается, что ваш файл данных имеет такое же форматированиекак ваш пример, и что ваши векторы появляются в числовом порядке.

Код:

use strict;
use warnings;
use v5.10;

my @data;
my $tmp;

while (<DATA>) {
    if (/^\*+/) {                  # or some other way of separating vectors
        push @data, $tmp if $tmp;  # push buffer to array
        <DATA>;                    # discard header
        $tmp = "";                 # reset buffer
    } else {
        $tmp .= $_;                # buffer a new line
    }
}
push @data, $tmp;                      # push remaining buffer onto array
@data = map { [ split ] } @data;       # split string into array
for my $num (0 .. $#{$data[0]}) {
    say join " ", map $data[$_][$num], keys @data;
}


__DATA__
****
1     3.28044
0.06504   -0.20409   -0.08035    0.04603   -0.02034   -0.02343    0.03885
0.14025    0.01970   -0.00569    0.11391   -0.05271   -0.00874    0.25005
-0.02425    0.03969    0.13327    0.01054    0.09958    0.20857    0.08647
0.13883    0.12003    0.12859    0.05634    0.06415    0.02570    0.07466
-0.06541    0.04636    0.01246   -0.13691   -0.04270    0.03791   -0.15341
-0.02595   -0.01027   -0.15604   -0.08393   -0.00526   -0.16938   -0.09027
0.01573   -0.25999   -0.09350    0.01121   -0.24367   -0.01033    0.03059
-0.31268   -0.00040    0.02074   -0.17927   -0.01689   -0.02183   -0.03912
-0.01481   -0.03982    0.10507   -0.03446   -0.06896    0.20946   -0.00450
-0.17669    0.17617    0.08755   -0.21143    0.25313    0.12818   -0.13896
0.16625    0.06539
****
2     1.17147
0.05028    0.24209    0.07571    0.07015    0.26226    0.10552    0.09788
0.15535    0.10020    0.06248    0.07167    0.09337    0.06555   -0.05258
0.07777    0.05163   -0.08617   -0.01580    0.05087   -0.17374   -0.06483
0.03157   -0.18854   -0.12423    0.02388   -0.15753   -0.07304    0.00221
-0.12406   -0.11678   -0.00030   -0.07568   -0.07783   -0.00225   -0.10201
-0.09521    0.00373   -0.10066   -0.06755   -0.00386   -0.10808   -0.08343
-0.01420   -0.03899   -0.11123   -0.06186   -0.02282   -0.11633   -0.07596
0.03656   -0.14599   -0.07542    0.13621   -0.11299   -0.07350    0.22728
-0.02254   -0.07473    0.32577    0.01167   -0.09106    0.17148    0.10912
-0.01607    0.00303    0.19984   -0.01223   -0.16824    0.28827   -0.00879
-0.23259    0.16630
1 голос
/ 13 ноября 2011

Если я правильно понимаю проблему, я думаю, что этот скрипт AWK сработает, я постарался сделать его легким для чтения и понимания, поэтому довольно многословный скрипт:

####
# Use like:
# 
#  awk -f transpose.awk <Eigenvector file>
#
#  This script assumes that all Eigenvectors in the file, have the same number
#  of values. The script will output all Eigenvectors into columns e.g if three
#  Eigenvectors it will produce three columns of values.
#
####

BEGIN {
  # Keeps track of the number of Eigenvectors
  currentEV = 0;
}

# Signifies a new Eigenvector (EV)
$1 == "****" {
  newEV = "true";
  transpose = "true";
  next;
}

# Get the EV's number
newEV == "true" {
  newEV = "false";
  currentEV = $1;
  currentEVCol = 0; 
  next;
}

# Add all the values on the line, for the current EV, into the EV array
transpose == "true" {
  for (i=1; i<=NF; i++) {
    ev[currentEV,++currentEVCol] = $i;
  }
}

END {
  # Loop through the array and print EV's ou in columns
  for (i=1; i<=currentEVCol; i++) {
    for (j=1; j<=currentEV; j++) {
      printf ev[j,i] " ";
    }
    print "";
  }
}

Для краткостиверсия скопируйте следующее в файл с именем transpose.awk:

skip { skip = 0; next; }

$1 == "****" {
  EV++; EVC = 0; skip = 1;
  next;
}

NF && EV {
  for (i=1; i<=NF; i++) {
    EVA[EV,++EVC] = $i;
  }
}

END {
  for (i=1; i<=EVC; i++) {
    for (j=1; j<=EV; j++) {
      printf EVA[j,i] " ";
    }
    print "";
  }
}

и вызовите как $ awk -f transpose.awk file > transposedFile

1 голос
/ 13 ноября 2011

для awk-решения попробуйте следующее. Сохраните эти команды в файле s.awk:

/\*\*\*/{i++;accInd=0;next}
(i>0){for (k=1;k <= NF;k++){
        I=k+accInd
        a[i,I]=$k
    }
    accInd=accInd+(k-1)
}
END{for (n=3;n<=I;n++){
       for (m=1;m<=i;m++){
           printf "%f\t", a[m,n]
        }
        printf "\n"
    }
}

Затем запустите из командной строки эту команду:

$ awk -f s.awk file

HTH Крис

0 голосов
/ 14 ноября 2011

Скорее похоже на TLP, но немного чище, на мой взгляд.Также сохраняет собственное значение в отдельном массиве.По его словам, вы можете изменить <DATA> на <> и запустить как scriptname.pl mydata.dat (затем вы можете удалить тег __DATA__ и все, что после него тоже).

Используется дополнительный модуль Array::Transposeсделать транспонирование (установить с помощью команды cpan).Модуль Data::Dumper и его функция Dumper используются для визуализации.Биты grep { length } удаляют пустые элементы, найденные split, это, вероятно, можно устранить, удалив начальные пробелы, но это выглядело более надежным.

#!/usr/bin/env perl

use strict;
use warnings;

use Data::Dumper;
use Array::Transpose;

my $row = -1;
my @eigen;
my @data;

while( <DATA> ) {
  if (/\*+/) {
    #increment row number
    $row++;
    #next line is eigenvalue, keep it in @eigen
    my @line = grep { length } split( /\s+/, <DATA>);
    push @eigen, $line[-1];
    # move on to next line
    next;
  }
  next if $row < 0; #skip first block

  push @{ $data[$row] }, grep { length } split( /\s+/ );
}

my @transpose = transpose(\@data);

print Dumper \@eigen;
print Dumper \@transpose;

__DATA__
Eigenvector file: COVAR
   72   72
   42.27674   53.43516   43.10335   43.43889   53.15094   43.77146   43.17536
   52.49170   45.07565   42.10424   52.75460   45.74721   41.66882   52.21836
   47.00361   40.21403   51.86627   47.05245   39.75512   50.92583   47.83411
   38.36019   50.61541   48.00747   37.56547   51.66199   48.72199   36.29018
   51.70312   48.54869   35.35773   52.59045   49.19493   34.14085   51.90543
   49.78376   33.43961   52.55997   50.66576   32.13812   52.14743   51.17284
   31.02647   52.41422   50.19470   30.02426   51.60068   50.14591   28.86206
   51.70417   49.28895   27.52769   51.49614   49.94867   27.52460   50.99136
   51.12215   26.37751   50.74786   51.93507   25.23025   50.04549   51.26765
   25.46212   49.27591   50.30035   24.47349   48.61017   49.51955   23.64720
   49.41136   48.60875
 ****
    1     3.28044
    0.06504   -0.20409   -0.08035    0.04603   -0.02034   -0.02343    0.03885
    0.14025    0.01970   -0.00569    0.11391   -0.05271   -0.00874    0.25005
   -0.02425    0.03969    0.13327    0.01054    0.09958    0.20857    0.08647
    0.13883    0.12003    0.12859    0.05634    0.06415    0.02570    0.07466
   -0.06541    0.04636    0.01246   -0.13691   -0.04270    0.03791   -0.15341
   -0.02595   -0.01027   -0.15604   -0.08393   -0.00526   -0.16938   -0.09027
    0.01573   -0.25999   -0.09350    0.01121   -0.24367   -0.01033    0.03059
   -0.31268   -0.00040    0.02074   -0.17927   -0.01689   -0.02183   -0.03912
   -0.01481   -0.03982    0.10507   -0.03446   -0.06896    0.20946   -0.00450
   -0.17669    0.17617    0.08755   -0.21143    0.25313    0.12818   -0.13896
    0.16625    0.06539
 ****
    2     1.17147
    0.05028    0.24209    0.07571    0.07015    0.26226    0.10552    0.09788
    0.15535    0.10020    0.06248    0.07167    0.09337    0.06555   -0.05258
    0.07777    0.05163   -0.08617   -0.01580    0.05087   -0.17374   -0.06483
    0.03157   -0.18854   -0.12423    0.02388   -0.15753   -0.07304    0.00221
   -0.12406   -0.11678   -0.00030   -0.07568   -0.07783   -0.00225   -0.10201
   -0.09521    0.00373   -0.10066   -0.06755   -0.00386   -0.10808   -0.08343
   -0.01420   -0.03899   -0.11123   -0.06186   -0.02282   -0.11633   -0.07596
    0.03656   -0.14599   -0.07542    0.13621   -0.11299   -0.07350    0.22728
   -0.02254   -0.07473    0.32577    0.01167   -0.09106    0.17148    0.10912
   -0.01607    0.00303    0.19984   -0.01223   -0.16824    0.28827   -0.00879
   -0.23259    0.16630
0 голосов
/ 13 ноября 2011

Если вы готовы к программированию на c ++, вы можете использовать Boost :: regex или flex / bison .

...