Вопрос или проблема
У меня есть файл CSV с семью числами в строке, как показано ниже:
1083,20,28,42,23,10,43
1084,20,5,29,59,40,33
1085,39,50,21,12,40,55
1086,45,4,6,23,10,2
1087,36,46,28,32,3,20
Я хочу оставить первое число на месте (столбец 1) и отсортировать столбцы со 2 по 7, чтобы файл выглядел так:
1083,10,20,23,28,42,43
1084,5,20,29,33,40,59
1085,12,21,39,40,50,55
1086,2,4,6,10,45,23
1087,3,20,28,32,36,46
Как я могу сделать это с помощью awk
, sed
и т. д.?
Спасибо
С помощью perl
:
perl -F, -lape '$_ = join ",", shift @F, sort {$a <=> $b} @F' < input.csv
С помощью GNU awk
:
gawk -F, '
{
split($0, a)
printf "%s", a[1]
delete a[1]
n = asort(a)
for (i = 1; i <= n ; i++) printf "%s", FS a[i]
print ""
}' < input.csv
Или с использованием библиотеки join.awk
(спасибо @WeijunZhou)
gawk -i join -F, -v OFS=, '
{
split($0, a)
first = a[1]
delete a[1]
n = asort(a)
print first, join(a, 1, n, OFS)
}'
Вашей проблемой является то, что у вас файлы с концами строк MAC (\r), в то время как команды, которые вы выполняете, предполагают использование концов строк Unix (\n).
Используйте Perl
:
$ perl -l015 -F, -0015 -pae '$_ = join ",", shift @F, sort { $a <=> $b } @F' input.csv
Опции:
-l
устанавливаетORS
в\r
= восьмеричное 15.-0
устанавливаетRS
в\r
= восьмеричное 15.-p
будет перебирать ваш файл CSV построчно. Строка отделяется от входного файла с помощью RS, который установлен как\r
с помощью опции-0
.-F
устанавливает разделитель полей как запятая для каждой строки, по мере её чтения.-a
разбивает каждую строку по мере её чтения на поля и сохраняет их в массиве@F
.- Примечание: порядок предоставления опций важен.
Таким образом, вывод, который вы получите, также будет иметь окончания строк MAC. Вот почему вы не видите ваш ожидаемый вывод, а все выводимые строки кажутся сжатыми в одну строку, основываясь на всех предложенных здесь решениях.
Это использует Miller (mlr
), чтобы превратить текущую запись в массив, отсортировать её (исключая первый элемент), а затем переписывает отсортированные элементы обратно в запись:
$ mlr --nidx --fs comma put 'for (k,v in sort(arrayify($*)[2:-1])) { $[k+1] = v }; ' file
1083,10,20,23,28,42,43
1084,5,20,29,33,40,59
1085,12,21,39,40,50,55
1086,2,4,6,10,23,45
1087,3,20,28,32,36,46
Данные читаются и записываются как индексированный файл, разделенный запятыми. Вы также можете использовать данные как файл CSV без заголовков (в данном случае это не имеет значения):
$ mlr --csv -N put 'for (k,v in sort(arrayify($*)[2:-1])) { $[k+1] = v }; ' file
1083,10,20,23,28,42,43
1084,5,20,29,33,40,59
1085,12,21,39,40,50,55
1086,2,4,6,10,23,45
1087,3,20,28,32,36,46
Для простого csv
без кавычек попробуйте следующее:
while IFS= read -r l; do
col1=$(printf '%s' "$l" | cut -d, -f1)
printf '%s,' "$col1"
printf '%s' "$l" | cut -d, -f2- | grep -o "[0-9]*" | sort -n | paste -sd,
done < file
Попробовал с помощью следующего метода, сочетания awk и sed
j=awk '{print NR}' filename | sort -nr| sed -n '1p'
for ((i=1;i<=$j;i++)); do k=`awk -F "," -v i="$i" 'NR==i {print $1}' i.txt` ;echo $k;awk -F "," -v i="$i" 'NR==i {$1=" ";print $0}' i.txt| sed -r "s/^\s+//g"| perl -pne "s/ /\n/g"| sort -n| perl -pne "s/\n/ /g";echo " "| sed "s/.*/&\n/g";done|sed '/^$/d'| sed "N;s/\n/ /g"| sed "s/ /,/g"| sed "s/\,*$//g"
вывод
1083,10,20,23,28,42,43
1084,5,20,29,33,40,59
1085,12,21,39,40,50,55
1086,2,4,6,10,23,45
1087,3,20,28,32,36,46
Ответ или решение
Для решения задачи сортировки элементов в CSV-файле, где необходимо оставить первый элемент строки на месте, а остальные значения отсортировать по возрастанию, можно использовать сразу несколько инструментов, таких как awk
, perl
, mlr
, и другие. Каждый из них имеет свои особенности, но для начала важно понять теоретическую основу и пример применения каждого инструмента, прежде чем выбрать наиболее подходящий.
Теория
CSV (Comma-Separated Values) – это текстовый формат, который используется для представления табличных данных. В данном случае, файл содержит строки, каждая из которых состоит из семи чисел, разделённых запятыми. Первая колонка представляет собой идентификатор строки и должна оставаться без изменений, тогда как остальные значения должны быть отсортированы по возрастанию.
Примеры инструментов
1. Perl
Perl – это мощный язык программирования, особенно подходящий для работы с текстами и строками. В приведённом ниже решении Perl используется для разбивки строки на элементы, сортировки чисел и объединения их обратно в строку.
perl -F, -lape '$_ = join ",", shift @F, sort {$a <=> $b} @F' < input.csv
Объяснение:
-F,
указывает Perl разбивать входные данные на массив @F, используя запятую как разделитель.-lape
последовательно обрабатывает каждую строку, разделяет строку, сортирует, а затем объединяет элементы.$_ = join ",", shift @F, sort {$a <=> $b} @F
выполняет сортировку элементов со второго по последний, оставляя первый элемент (идентификатор) на месте.
2. GNU Awk
GNU Awk – это текстовый процессор, который хорошо подходит для обработки и анализа текстов.
gawk -F, '
{
split($0, a)
printf "%s", a[1]
delete a[1]
n = asort(a)
for (i = 1; i <= n ; i++) printf "%s", FS a[i]
print ""
}' < input.csv
Объяснение:
gawk
используется для работы с CSV-файлами с разделителем – запятой-F,
.split($0, a)
разделяет текущую строку на массивa
.delete a[1]
удаляет первый элемент из массива (идентификатор).asort(a)
сортирует массив от второго до последнего элемента.printf
иprint
формируют строку вывода, добавляя снова первый элемент (идентификатор) и отсортированные значения.
3. Miller (mlr)
Miller – это инструмент для обработки CSV-файлов, qui делает обработку табличных данных особенно простой с интуитивно понятным синтаксисом.
mlr --nidx --fs comma put 'for (k,v in sort(arrayify($*)[2:-1])) { $[k+1] = v }; ' input.csv
Объяснение:
--nidx
и--fs comma
говорит Miller работать с файлами, где поля не имеют заголовков и разделяются запятыми.sort(arrayify($*)[2:-1])
преобразует строку в массив, сортирует его элементы начиная со второго и возвращает обратно.
Применение
Эти примеры позволяют выбрать наиболее подходящий инструмент в зависимости от среды и предпочтений. Например, если задача выполняется на сервере без установленного perl
, Awk может стать отличной альтернативой. Если требуется более современный и легкий в использовании инструмент, тогда выбор может пасть на Miller.
Кроме синтаксиса и команд, важно учесть настройки локализации и обработки строки. Например, окончание строк в файлах может различаться между системами (Unix/Linux, Windows, MacOS), что потенциально может вызвать проблемы при выполнении скриптов.
В заключение, использование скриптов и утилит, таких как perl
, gawk
, и mlr
, позволяет эффективно работать с CSV файлами, выполняя сортировку или другие операции над данными. Выбор конкретного решения должен основываться на доступности инструментов, удобстве использования и специфическом контексте задачи.