Как отсортировать столбцы на основе первой строки?

Вы можете использовать IFS=newline (предполагая, что ни одно имя файла не содержит newline), но вы должны установить его во внешней оболочке ДО подстановки:

$ ls -1
a file with spaces
able
alpha
baker
boo hoo hoo
bravo
$ # note semicolon here; it's not enough to be in the environment passed
$ # to printf, it must be in the environment OF THE SHELL WHILE PARSING
$ IFS=$'\n'; printf '%s\n' --afiles $(find . -name 'a*') --bfiles $(find . -name 'b*')
--afiles
./able
./a file with spaces
./alpha
--bfiles
./bravo
./boo hoo hoo
./baker

С zsh, но не bash вы можете использовать и null $'\0'. Даже в bash можно обработать newline, если есть один достаточно странный символ, который никогда не используется, например

 IFS=$'\1'; ... $(find ... -print0 | tr '\0' '\1') ...

Однако, этот подход не обрабатывает дополнительную просьбу, которую вы сделали в комментариях к ответу @steeldriver, опустить --afiles, если find a пуст.

12
07.06.2017, 17:06
8 ответов

Я не знаю, считаете ли вы это хорошим ответом, но...

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

SELECT column1, column2, ... column-n FROM my_temp_table

Вы можете использовать другие фильтры или преобразования по мере необходимости. Затем вы можете переформатировать вывод по своему усмотрению.

Все эти задачи можно было бы запрограммировать в виде bash-скрипта и объединить выходные данные с помощью конвейеров.

Иногда я использовал команду «pv», чтобы увидеть прогресс вывода между командами.

Чтобы импортировать набор данных, вы можете запрограммировать ETL с помощью Pentaho Data Integration.

0
27.01.2020, 19:54

Использование модуля Perl Sort::Naturally

для ввода данных

ID M2 M5 M8 M1 M3 M9 M700000
A1 m1,2 m1,5 m1,8 m1,1 m1,3 m1,9 m1,7000000
A2 m2,2 m2,5 m2,8 m2,1 m2,3 m2,9 m2,7000000
A3 m3,2 m3,5 m3,8 m3,1 m3,3 m3,9 m3,7000000
A1000 m1000,2 m1000,5 m1000,8 m1000,1 m1000,3 m1000,9 m1000,7000000
perl -MSort::Naturally -lane '
  if ($. == 1) {
    @indices = (0, map  { $_->[0] }
                   sort { ncmp($a->[1], $b->[1]) }
                   map  { [$_, $F[$_]] }
                   1..$#F
               );
    $, = " ";
  }
  print @F[@indices]
' test.data

выход

ID M1 M2 M3 M5 M8 M9 M700000
A1 m1,1 m1,2 m1,3 m1,5 m1,8 m1,9 m1,7000000
A2 m2,1 m2,2 m2,3 m2,5 m2,8 m2,9 m2,7000000
A3 m3,1 m3,2 m3,3 m3,5 m3,8 m3,9 m3,7000000
A1000 m1000,1 m1000,2 m1000,3 m1000,5 m1000,8 m1000,9 m1000,7000000
6
27.01.2020, 19:54

Возможно, это тоже поможет вам.

  1. Сначала вы можете использовать транспонирование вашего файла (один из https://stackoverflow.com/questions/1729824/an-efficient-way-to-transpose-a-file-in-bash)
  2. Сортировка первого столбца с помощью команды сортировки.
  3. Снова транспонировать.

Пример:

$ echo "ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln" | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}' | sort -n | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}'
ID M1 M2 M3 M5 .....M7000000 M8 M9
Animal1 1 1 0 0 .....1 2 2
Animal2 0 0 1 1 .....0 2 1
Animal3 1 2 2 1 .....0 0 1
.       
.       
.       
.       
Animaln    
0
27.01.2020, 19:54

Если у вас есть GNU awk, вы можете попробовать это:

NR == 1 {
    for (i = 2; i <= NF; i++) {
        columns[substr($i, 2)] = i;
    }
    count = asorti(columns, sorted, "@ind_num_asc");
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" M%s", sorted[i]);
        indx[i] = columns[sorted[i]];
    }
    print "";
    next;
}
{
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" %s", $(indx[i]));
    }
    print "";
}
0
27.01.2020, 19:54

В Python:

from csv import DictReader, DictWriter
with open('in_file.csv') as infile, open('out_file.csv') as outfile:
  reader = DictReader(infile)
  writer = DictReader(outfile, fieldnames=sorted(reader.fieldnames))
  writer.writerows(reader)
0
27.01.2020, 19:54

С GNUdatamashи GNUsort:

datamash transpose -t ' ' -H <file_in.csv | sort -V | datamash transpose -t ' ' -H >file_out.csv

Это прекрасно работает для «достаточно малых» данных. Это может или не может работать с вашим файлом.

Редактировать:Приведенные ниже решения без транспозиций должны быть менее ресурсоемкими -.

10
27.01.2020, 19:54
perl -pale '
   $. == 1 and
   @I = map  { $_->[1] }
        sort { $a->[0] <=> $b->[0] }
        map  { [ $F[$_] =~ /^M(\d+)$/, $_ ] } 1..$#F;
   $_ = "@F[0, @I]";
' yourlargefile

  1. Для первой строки мы численно сортируем ее 2-й...последний столбцы, используя их числовые части после цифры M, встречающейся в начале, используя хорошо известную Schwartzian maneuver. Это дает нам индексы, переупорядоченные так, чтобы столбцы выходили в численно отсортированном порядке (M1, M2, M3,...)
  2. Остается только использовать эти индексы, полученные из @I, для повторного -размещения элементов @F.
  3. Назначение массива в виде двойных -кавычек преобразует его в строку с элементами, разделенными пробелами.
  4. Опция
  5. -pв Perl включает автопечать содержимого $_, -lдобавляет newline.
6
27.01.2020, 19:54

Если у вас установлена ​​утилитаrs, вы можете сделать это:

rs -c' ' -T | {
    stdbuf -i0 sed "1q"
    sort -V
} | rs -C' ' -T

Или все в одной строке:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • Первый rsтранспонирует входные данные (с разделенными пробелами -полями)
  • Группа команд :
    • sedчитает первую строку, выводит ее, затем завершает работу, оставляя остальную часть конвейера из rsнетронутой. stdbufтребуется для обеспечения того, чтобы sedчитал только до первой новой строки и не далее, отключив буферизацию ввода
    • sortостальные строки
  • Второй rsтранспонирует результирующий поток обратно в исходный формат.

rsустанавливается по умолчанию в MacOS. В системах Linux вам может потребоваться установить его -, например.

sudo apt install rs

Предупреждение:stdbufи sorts -Vотносятся к GNU -, поэтому они не будут работать на немодифицированной MacOS.

4
27.01.2020, 19:54

Теги

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