在 UNIX 排序中有忽略标题行的方法吗?

我有一个固定宽度的字段文件,正在尝试使用 UNIX (在我的例子中是 Cygwin) sort 实用程序对其进行排序。

问题是在文件的顶部有一个两行的标题,它被排序到文件的底部(因为每个标题行都以冒号开头)。

有没有一种方法可以告诉 sort“传递未排序的前两行”,或者指定一个排序,将冒号行排序到顶部——如果有帮助的话,剩下的行总是以一个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
114610 次浏览

您可以使用 tail -n +3 <file> | sort ...(tail 将从第3行输出文件内容)。

(head -n 2 <file> && tail -n +3 <file> | sort) > newfile

圆括号创建一个子 shell,包装 stdout,这样您就可以通过管道或重定向它,就好像它来自一个命令一样。

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

如果您不介意使用 awk,您可以利用 awk的内置管道能力

例如。

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

这将逐字打印前两行,并通过 sort传送其余的代码。

请注意,这样做有一个非常特殊的优势,那就是能够有选择地对部件进行排序 管道输入。所有其他建议的方法将只排序可以读取多次的普通文件。这对任何东西都管用。

使用 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)

下面是一个适用于管道数据的版本:

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

如果标题有多行:

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

这个解决方案来自 给你

下面是从其他答案派生的 bash shell 函数。它同时处理文件和管道。第一个参数是 stdin 的文件名或“-”。将其余参数传递给排序。举几个例子:

$ 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
}

它只需要两行代码..。

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

对于数值数据,-n 是必需的。对于 alpha 排序,-n 不是必需的。

示例文件:
$cat test. txt

标题
8
5
100
1
-1

结果:
$Cat a.tmp

标题
-1
1
5
8
100

这与 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;
cat file_name.txt | sed 1d | sort

这就是你想要的。

这里有一个 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 进行排序。这最初是由 Dave 提出的,并进行了修改以采用排序参数。我们依赖于这样一个事实: 如果我们使用管道,那么 $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

在简单的情况下,sed可以优雅地完成这项工作:

    your_script | (sed -u 1q; sort)

或者相当于,

    cat your_data | (sed -u 1q; sort)

键在 1q中——打印第一行(头部)并退出(将剩余的输入留给 sort)。

对于给出的示例,2q将起作用。

-u开关(未缓冲)是那些 sed(特别是 GNU)所必需的,否则它们会以块的形式读取输入,从而消耗您希望通过 sort读取的数据。

另一个简单的变化,所有其他,读取一次文件

HEADER_LINES=2
(head -n $HEADER_LINES; sort) < data-file.dat