Как получить среднее значение нескольких данных подряд из нескольких папок

Разбиение на пробелы происходит в вашей команде read, но вам это все равно не нужно. Кроме того, ваша ifлогика ошибочна. Это будет работать, только если my_dirравно ., иначе findне будет генерировать .на выходе. Наконец, вы указываете в своем примере, что вам нужны только имена каталогов, а не весь путь, но так, как вы его написали, findпередаст путь к стандартному выводу.

Вот более простое решение:

find "$my_dir" -maxdepth 1 -type d -exec basename {} \;|tail -n +2

Хитрость здесь заключается в команде tail. Вы хотите исключить начальный каталог($my_dir)из вывода.findвсегда сначала выводит этот каталог (, если вы явно не требуете глубины -первого обхода ), поэтому вам просто нужно удалить первую строку из результирующего вывода.

2
29.05.2021, 22:00
3 ответа
$ paste data*.txt |
    awk -v numOutFlds=4 '{
        numFiles = NF / numOutFlds
        for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) {
            sum = 0
            for (fileNr=1; fileNr<=numFiles; fileNr++) {
                inFldNr = outFldNr + ((fileNr - 1) * numOutFlds)
                sum += $inFldNr
            }
            printf "%g%s", sum/numFiles, (outFldNr<numOutFlds ? OFS : ORS)
        }
    }' |
    column -t
0.75  1.25  3     3.25
4     0.75  0.75  3
2.25  1     1.5   1.75
2     1.5   2     1
3
28.07.2021, 11:28

Предполагая, что я правильно интерпретировал это, вы также можете сделать что-то вроде:

awk(POSIX):

awk -v n_col=4 '
NF != n_col { next }
FILENAME != file {
    file = FILENAME
    k = 0
}
{
    for (i = 1; i <= n_col; ++i)
        A[k++] += $i
}
END {
    n_files = ARGC - 1
    for (i = 0; i < k; ) {
        printf "%2.3f%s", A[i] / n_files,
            ++i % n_col == 0 ? "\n" : " "
    }
}
' data*.txt

perl:

Я уверен, что это можно сделать лучше, но попробуй.

./script.pl <COLUMNS> data*.txt
#!/usr/bin/env perl

use strict;
use warnings;

my @data;
my $cols = $ARGV[0];
my $ac = $#ARGV;
shift;
for (@ARGV) {
    my $k = 0;
    open my $fh, '<', $_
        or die "Cannot open '$_' - $!";
    local $/;
    my $fdata = <$fh>;
    close $fh;
    for ($fdata) {
        $data[$k++] += $_ for split;
    }
}

my $i = 0;
for (@data) {
    printf "%.3f%s", $_ / $ac, ++$i % $cols ? "\t" : "\n";
}


bash:(Медленно)

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

Обратите внимание, что хотя это и выполнимо, это не лучший инструмент для работы.

Использует башизм для mapfile, read -aи т. д.

./script <COLUMNS> data*.txt

#!/bin/bash

declare -i res=1000
declare -i dec=$(( ${#res} - 1 ))
declare -i n_files
declare -i n_columns
declare -a A

process()
{
    local m a
    mapfile -t m< "$1"
    read -ra a<<< "${m[@]}"
    for (( i = 0; i < ${#a[*]}; ++i )); do
        (( A[i] += a[i] ))
    done
    (( ++n_files ))
}

n_columns=$1
shift
for f in "$@"; do
    process "$f"
done

for (( i = 0; i < ${#A[@]}; ++i )); do
    (( (i + 1) % n_columns == 0 )) && sep=$'\n' || sep=' '
    printf "%3.${dec}f%s" "$(( res * A[i] / n_files ))e-$dec" "$sep"
done

альтернативный метод печати "плавающий":

    (( d = A[i] * res / n_files ))
    printf "%3d.%0${dec}d%s" "$(( d / res ))" "$(( d % res ))" "$sep"

Далее sed... нет , поверьте, я только связываю это:Дополнение с 'sed' ;)

1
28.07.2021, 11:28

Можно обойтись настольным калькулятором РПНdc

paste./*.txt |
dc -e "2k #2 decimal digits output
[q]sq
[0dddsasbscsd]si # initialize the four registers
[la+sa lb+sb lc+sc ld+sd z3<u]su # update the four registers
[ld4/n9an lc4/n9an
 lb4/n9an la4/n10an lix]sp # print results
[?z0=q lux lpx z0=?]s?
lix l?x
"
.75 1.25    3.00    3.25
4.00   .75.75 3.00
2.25    1.00    1.50    1.75
2.00    1.50    2.00    1.00

Perl можно использовать следующим образом:

paste *.txt |
perl -lane '
  my @avgs;
  while (@F >= 4) {
    my @tmp = splice(@F, 0, 4);
    $avgs[$#tmp] += pop(@tmp) while @tmp;
  }
  print join "\t", map { sprintf "%.2f", $_/4.0 } @avgs;
' - 

Мы можем использовать GNU sed в сотрудничестве с bc для получения вывода.

n='(\S+)'
paste./*.txt |
sed -Ee "
  s/\s+/ /g;s/^ | \$//g
  s/\$/ /;s/ /\n/4;ta
  :a
    s/^$n $n $n $n\n$n $n $n $n (.*)/printf '%d %d %d %d\n%s' \$((\1 + \5)) \$((\2 + \6)) \$((\3 + \7)) \$((\4 + \8)) '\9'/e
    s/\n/&/
  ta
  s/.*/printf '%d\/4\n' &|bc -l|paste -s/e
  s/(\...)\S*/\1/g
  s/(^|\t)\./\10./g
" -
2
28.07.2021, 11:28

Теги

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