Ответ 1
(head -n 2 <file> && tail -n +3 <file> | sort) > newfile
Скобки создают подоболочку, завершая stdout, чтобы вы могли ее перенести или перенаправить, как если бы она появилась из одной команды.
У меня есть файл с фиксированной шириной, который я пытаюсь сортировать с помощью утилиты сортировки UNIX (Cygwin, в моем случае).
Проблема заключается в том, что в верхней части файла находится двухстрочный заголовок, который сортируется в нижней части файла (поскольку каждая строка заголовка начинается с двоеточия).
Есть ли способ рассказать сортировку либо "передать первые две строки по несортированному", либо указать порядок, который сортирует строки двоеточия в верхней части - остальные строки всегда начинаются с 6-значного числа (что фактически ключ, который я сортирую), если это помогает.
Пример:
: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
(head -n 2 <file> && tail -n +3 <file> | sort) > newfile
Скобки создают подоболочку, завершая stdout, чтобы вы могли ее перенести или перенаправить, как если бы она появилась из одной команды.
Если вы не против использования awk
, вы можете использовать awk
встроенные возможности канала
например.
extract_data | awk 'NR<3{print $0;next}{print $0| "sort -r"}'
Это печатает первые две строки дословно, а остальные - через sort
.
Обратите внимание, что это имеет очень специфическое преимущество: возможность выборочного сортировки частей входного канала. все другие предлагаемые методы будут сортировать только обычные файлы, которые можно прочитать несколько раз. Это работает на что угодно.
Вот версия, которая работает с данными по каналам:
(read -r; printf "%s\n" "$REPLY"; sort)
Если ваш заголовок имеет несколько строк:
(for i in $(seq $HEADER_ROWS); do read -r; printf "%s\n" "$REPLY"; done; sort)
Это решение от здесь
Вы можете использовать tail -n +3 <file> | sort ...
(хвост выведет содержимое файла из третьей строки).
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
Требуется только 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
Итак, здесь функция 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
С 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)
Здесь bash функция оболочки, полученная из других ответов. Он обрабатывает файлы и каналы. Первый аргумент - имя файла или '-' для stdin. Остальные аргументы передаются для сортировки. Несколько примеров:
$ hsort myfile.txt
$ head -n 100 myfile.txt | hsort -
$ hsort myfile.txt -k 2,2 | head -n 20 | hsort - -r
Функция оболочки:
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
}
Это то же самое, что и ответ Яна Шербина, но моя реализация: -
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;
В простых случаях sed
может выполнить работу элегантно:
your_script | (sed -u 1q; sort)
или эквивалентно,
cat your_data | (sed -u 1q; sort)
Ключ находится в 1q
- печатать первую строку (заголовок) и выходить (оставляя оставшиеся данные для sort
).
Для приведенного примера 2q
сделает 2q
дело.
Переключатель -u
(небуферизованный) необходим для тех sed
(в частности, для GNU), которые в противном случае считывали бы входные данные кусками, тем самым потребляя данные, которые вы хотите вместо этого пройти через sort
.
cat file_name.txt | sed 1d | sort
Это сделает то, что вы хотите.