Вам следует использовать PinguyBuilder
PinguyBuilder - это скрипт, который позволяет создавать индивидуальный Live CD / Live USB (remaster) Ubuntu или Linux Mint, который можно использовать либо как распространяемый ISO, либо как резервная копия.
awkрешение длялюбоеколичество столбцов (вы упомянули образец файла с 13 столбцами):
Допустим, у нас есть файл расширенного примера:
1 10 15 10 99
3 34 20 20 111
1 4 22 22 33
3 32 33 12 5
5 3 46 44 9
2 2 98 55 55
4 20 100 11 33
3 13 23 77 23
4 50 65 33 66
1 40 76 78 16
2 20 22 98 93
awk '{ for(i=2;i<=NF;i++) { if (!($1 in a) || $i > a[$1][i]) a[$1][i]=$i }}
END{ r=""; for(i in a) { r=i; for(j in a[i]) r=r OFS a[i][j]; print r }
}' OFS='\t' file
Выход:
1 40 76 78 99
2 20 98 98 93
3 34 33 77 111
4 50 100 33 66
5 3 46 44 9
Вот один из способов в awk:
$ awk '{
if($2 > a[$1][2]){
a[$1][2] = $2
}
if($3 > a[$1][3]){
a[$1][3] = $3
}
}
END{
for(i in a){
printf "%s ", i;
for(c=1; c<=maxFields; c++){
if(c in a[i]){
printf "%s ",a[i][c]
}
}
print ""
}' ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
Сценарий просто использует двухмерный -массив a
для хранения максимального значения для каждого из двух столбцов. Для каждого значения i
1-го столбца a[i][2]
будет содержать максимальное значение, найденное для i
во 2-м столбце, и a[i][3]
максимальное значение для 3-го столбца. После обработки всего файла мы печатаем максимальные значения для каждого значения i
.
Если у вас более 3 столбцов, вы можете использовать:
awk '{
for(c=2; c<=NF; c++){
if($c > a[$1][c]){
a[$1][c] = $c;
}
}
}
END{
for(i in a){
printf "%s: ", i;
for(c in a[i]){
printf "%s ",a[i][c]
}
print ""
}
}' ifile.dat
Обратите внимание, что приведенное выше решение не будет работать корректно с отрицательными значениями или если у вас может быть 0
и т. д., и оно может привести к неправильному порядку полей, поскольку awk
не обязательно обходит массивы по порядку. Более надежный подход:
awk '{
for(c=2; c<=NF; c++){
if(!(c in a) || $c > a[$1][c]){
a[$1][c] = $c;
}
}
}
END{
for(i in a){
printf "%s ", i;
for(c in a[i]){
printf "%s ",a[i][c]
}
print ""
}
}' ifile.dat
Datamash GNU отлично подходит для подобных вещей:
$ datamash -sW groupby 1 max 2,3 < ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
Чтобы обрабатывать большее количество столбцов, вы можете указать диапазон , например.
datamash -sW groupby 1 max 2-13 < ifile.dat
Использование сортировки в качестве основного инструмента:
sort ifile.dat -k1,1 -k2,2nr | sort -uk1,1 | awk '{print $1,$2}' \
| paste - <(sort ifile.dat -k1,1 -k3,3nr | sort -uk1,1 | awk '{print $3}')
#!/usr/bin/env python3
import sys
from collections import OrderedDict as od
# read data in the file first, create data dictionary of column lists
data = od()
with open(sys.argv[1]) as f:
for line in f:
columns = line.strip().split()
how_many = len(columns)-1
if columns[0] not in data.keys():
data[ columns[0] ] = [ [] for i in range(how_many) ]
for index in range(how_many):
data[ columns[0] ][index].append( int(columns[index+1]) )
# post process all the created lists of lists by applying max() on each
for item in sorted(data.keys()):
print(item,end=" ")
for array in data[item]:
print(max(array),end=" ")
print("")
С примером ввода, предоставленным OP:
$./columns_max.py input.txt
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
С расширенным примером в ответе Романа Перехреста:
$./columns_max.py input.txt
1 40 76 78 99
2 20 98 98 93
3 34 33 77 111
4 50 100 33 66
5 3 46 44 9
Основная идея состоит в том, что мы создаем словарь из элементов первого столбца. Таким образом, в словаре у нас будут ключи 1,2,3,4 и 5. Каждое соответствующее значение для элемента словаря представляет собой список списков, где каждому под-списку соответствует столбец. Итак, для ключа 1 у нас будет список с двумя списками, где первый список предназначен для всех элементов столбца 2, а второй список — для всех элементов столбца 3. В основном это:
('1', [ ['10', '4', '40'], ['15', '22', '76']] )
Есть очень хорошая функция max()
, которая позволяет нам взять числовой список и извлечь из него самый большой элемент. Все, что нам нужно сделать, это перебрать каждый ключ, удалить все списки и применить к ним функцию max()
.
perl -lane '
$F[$_] > $A[$F[0]-1][$_] and $A[$F[0]-1][$_] = $F[$_] for 1.. $#F}{
print 1+$_, "@{$A[$_]}" for grep defined $A[$_], 0.. $#A
' ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
Data structure involved is an `LoL` (list of lists) assuming that the
column 1 data is nonnegative.
@A = (
[column_2_max_for_idx1, column_3_max_for_idx1, column_4_max_for_idx1,...],
[........],
);