it-swarm.com.ru

Есть ли способ игнорировать строки заголовка в сортировке UNIX?

У меня есть файл с фиксированной шириной поля, который я пытаюсь отсортировать с помощью утилиты сортировки UNIX (Cygwin, в моем случае).

Проблема в том, что в верхней части файла находится двухстрочный заголовок, который сортируется в конец файла (так как каждая строка заголовка начинается с двоеточия).

Есть ли способ указать сортировке «пропустить первые две строки через несортированные» или указать порядок, который сортирует строки двоеточия сверху - остальные строки всегда начинаются с 6-значного числа (которое на самом деле является ключом I сортирую) если что поможет.

Пример:

:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
500123TSTMY_RADAR00
222334NOTALINEOUT01
477821USASHUTTLES21
325611LVEANOTHERS00

следует отсортировать по:

:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
222334NOTALINEOUT01
325611LVEANOTHERS00
477821USASHUTTLES21
500123TSTMY_RADAR00
80
Rob Gilliam
(head -n 2 <file> && tail -n +3 <file> | sort) > newfile

Скобки создают подоболочку, заключающую в себе стандартный вывод, так что вы можете передать его или перенаправить, как если бы он был получен от одной команды.

92
BobS

Если вы не возражаете против использования awk, вы можете воспользоваться встроенными возможностями канала awk

например.

extract_data | awk 'NR<3{print $0;next}{print $0| "sort -r"}' 

Это печатает первые две строки дословно и передает остальные через sort.

Обратите внимание, что это имеет очень специфическое преимущество, заключающееся в возможности выборочной сортировки частей все другие предложенные методы будут сортировать только простые файлы, которые могут быть прочитаны несколько раз. Это работает на что угодно.

41
Dave

Вот версия, которая работает на переданных данных:

(read -r; printf "%s\n" "$REPLY"; sort)

Если ваш заголовок имеет несколько строк:

(for i in $(seq $HEADER_ROWS); do read -r; printf "%s\n" "$REPLY"; done; sort)

Это решение от здесь

26
freeseek

Вы можете использовать tail -n +3 <file> | sort ... (tail выведет содержимое файла из 3-й строки).

6
Anton Kovalenko
head -2 <your_file> && nawk 'NR>2' <your_file> | sort

пример:

> cat temp
10
8
1
2
3
4
5
> head -2 temp && nawk 'NR>2' temp | sort -r
10
8
5
4
3
2
1
4
Vijay

Это займет всего 2 строки кода ...

head -1 test.txt > a.tmp; 
tail -n+2 test.txt | sort -n >> a.tmp;

Для числовых данных требуется -n. Для альфа-сортировки -n не требуется.

Пример файла:
$ cat test.txt

заголовок
8
5
100
1
-1 

Результат:
$ cat a.tmp

заголовок
-1
1
5
8
100

1
Ian Sherbin

Это то же самое, что и ответ Яна Шербина, но моя реализация такова:

cut -d'|' -f3,4,7 $arg1 | uniq > filetmp.tc
head -1 filetmp.tc > file.tc;
tail -n+2 filetmp.tc | sort -t"|" -k2,2 >> file.tc;
0
Bik

Вот функция оболочки bash, полученная из других ответов. Он обрабатывает как файлы, так и каналы. Первый аргумент - это имя файла или '-' для стандартного ввода. Остальные аргументы передаются для сортировки. Пара примеров:

$ hsort myfile.txt
$ head -n 100 myfile.txt | hsort -
$ hsort myfile.txt -k 2,2 | head -n 20 | hsort - -r

Функция Shell:

hsort ()
{
   if [ "$1" == "-h" ]; then
       echo "Sort a file or standard input, treating the first line as a header.";
       echo "The first argument is the file or '-' for standard input. Additional";
       echo "arguments to sort follow the first argument, including other files.";
       echo "File syntax : $ hsort file [sort-options] [file...]";
       echo "STDIN syntax: $ hsort - [sort-options] [file...]";
       return 0;
   Elif [ -f "$1" ]; then
       local file=$1;
       shift;
       (head -n 1 $file && tail -n +2 $file | sort $*);
   Elif [ "$1" == "-" ]; then
       shift;
       (read -r; printf "%s\n" "$REPLY"; sort $*);
   else
       >&2 echo "Error. File not found: $1";
       >&2 echo "Use either 'hsort <file> [sort-options]' or 'hsort - [sort-options]'";
       return 1 ;
   fi
}
0
JonDeg

Итак, вот функция bash, где аргументы в точности похожи на sort. Вспомогательные файлы и трубы.

function skip_header_sort() {
    if [[ $# -gt 0 ]] && [[ -f ${@: -1} ]]; then
        local file=${@: -1}
        set -- "${@:1:$(($#-1))}"
    fi
    awk -vsargs="$*" 'NR<2{print; next}{print | "sort "sargs}' $file
}

Как это устроено. Эта строка проверяет, существует ли хотя бы один аргумент и является ли последний аргумент файлом.

    if [[ $# -gt 0 ]] && [[ -f ${@: -1} ]]; then

Это сохраняет файл в отдельный аргумент. Так как мы собираемся стереть последний аргумент.

        local file=${@: -1}

Здесь мы удалим последний аргумент. Так как мы не хотим передавать это как аргумент сортировки.

        set -- "${@:1:$(($#-1))}"

Наконец, мы выполняем часть awk, передавая аргументы (минус последний аргумент, если это был файл) для сортировки в awk. Это было изначально предложено Дейвом и модифицировано, чтобы принимать аргументы сортировки. Мы полагаемся на тот факт, что $file будет пустым, если мы будем использовать трубопровод, поэтому игнорируется.

    awk -vsargs="$*" 'NR<2{print; next}{print | "sort "sargs}' $file

Пример использования с разделенным запятыми файлом.

$ cat /tmp/test
A,B,C
0,1,2
1,2,0
2,0,1

# SORT NUMERICALLY SECOND COLUMN
$ skip_header_sort -t, -nk2 /tmp/test
A,B,C
2,0,1
0,1,2
1,2,0

# SORT REVERSE NUMERICALLY THIRD COLUMN
$ cat /tmp/test | skip_header_sort -t, -nrk3
A,B,C
0,1,2
2,0,1
1,2,0
0
flu

С Python:

import sys
HEADER_ROWS=2

for _ in range(HEADER_ROWS):
    sys.stdout.write(next(sys.stdin))
for row in sorted(sys.stdin):
    sys.stdout.write(row)
0
crusaderky