Удалите столбцы, сумма которых равна нулю.

Для более сложных деревьев перенаправления файловых дескрипторов есть pipexec, который попал в репозиторий Debian.

Воистину, это ограничение синтаксиса в BASH и в Bourne-подобных оболочках в целом.

3
13.04.2017, 15:37
3 ответа

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

cut $(awk 'NR>1{for(i=2;i<=NF;i++) s[i]+=$i}END{printf("%s", "-f 1");
for (i=2;i<=NF;i++) {if (s[i]) printf(",%s", i)}}' infile) infile

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

0
27.01.2020, 21:21

, чтобы удалить столбец

c.awk:

 { for(i=1;i<=NF;i++) { line[NR][i]=$i ; col[i]+=$i ;} }
END {
 for ( l=1 ; l<=NR ; l++ )
  {
    printf line[l][1]   "\t" ;
    for (c=2;c<=NF;c++) if (col[c]) printf line[l][c]  "\t" ;
    printf "\n" ;
  }
}

где

  • {for (i = 1; i <= NF; i ++) {line [NR] [i] = $ i; col [i] + = $ i;}} сохраняет всю строку (включая имена столбцов). Предложение
  • END печатает весь столбец, если count! = 0.
  • будьте осторожны, чтобы все данные хранились в памяти.

тест:

awk -f c.awk a
a   b       c
e   1       2
f   3       4
g   5       6

для строкового решения ...

попробуйте

 awk 'NR==1 {print } NR>1 { s=0 ; for(i=1;i<=NF;i++) s+=$i ; if (s) print ;}'

где

  • NR == 1 {print} print header
  • NR> 1 {s = 0; для (i = 1; i <= NF; i ++) s + = $ i; if (s) print;} проверка на 0 и печать, если нет
  • , вы можете начать с i = 2 , если первый столбец является именем строки.
  • остерегайтесь чисел с плавающей запятой, они не могут быть суммированы до 0.

обратите внимание, что это будет выводить строки, а не удалять из исходного файла.

2
27.01.2020, 21:21

Это может быть проще с perl, если вы хотите сохранить интервалы:

perl -lne '
   $i = 0;
   for (/\S+\s*/g) {
      $cell[$.][$i] = $_;
      $sum[$i++] += $_
   }
   END{
     @keep=(0, grep {$sum[$_]} (1..$#sum));
     print((@{$cell[$_]})[@keep]) for (1..$.)
   }'

Это загружает весь файл в память. Чтобы избежать этого, вам понадобится два прохода в файле.

Это можно сделать с помощью комбинации awk и sed:

awk '
  NR>1{for (i=2; i<=NF; i++) sum[i]+=$i; if (NF>n) n = NF}
  END {
    for (;n>1;n--)
      if (!sum[n])
        print "s/[^[:blank:]]\\{1,\\}[[:blank:]]*//" n
  }' < file | sed -f - file

awk генерирует сценарий sed для удаления столбцов, сумма которых равна 0. Команды s/[^[:blank:]]\{1,\}[[:blank:]]*//3 sed удалят столбцы с сохранением интервалов между остальными столбцами, но это будет довольно дорого, вы можете захотеть сделать это удаление в perl, если производительность является проблемой.

Для строк все гораздо проще:

perl -MList::Util=sum -lane 'print if $. == 1 or sum @F'
1
27.01.2020, 21:21

Теги

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