120

我有一个固定宽度字段文件,我正在尝试使用 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
4

12 回答 12

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

括号创建了一个子shell,将标准输出包裹起来,以便您可以通过管道传输或重定向它,就好像它来自单个命令一样。

于 2013-01-28T13:03:00.027 回答
98

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

例如。

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

这将逐字打印前两行并将其余部分通过管道传输sort

请注意,这具有非常特殊的优势,即能够有选择地对管道输入的部分进行排序。建议的所有其他方法只会对可以多次读取的普通文件进行排序。这适用于任何事情。

于 2014-03-09T11:54:32.897 回答
45

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

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

如果您的标题有多行:

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

这个解决方案来自这里

于 2014-12-08T23:11:14.613 回答
43

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

    your_script | (sed -u 1q; sort)

或等效地,

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

关键在于1q-- 打印第一行(标题)并退出(将其余输入留给sort)。

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

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

于 2019-05-15T14:31:37.440 回答
8

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

于 2013-01-28T12:56:17.640 回答
4
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
于 2013-01-28T13:13:10.150 回答
3

只需要两行代码...

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

于 2015-02-01T21:05:31.393 回答
2

所以这是一个 bash 函数,其中参数与排序完全相同。支持文件和管道。

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
于 2018-02-14T22:37:43.787 回答
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)
于 2014-10-21T12:28:00.977 回答
0

这是从其他答案派生的 bash shell 函数。它处理文件和管道。第一个参数是文件名或标准输入的“-”。剩余的参数被传递给排序。几个例子:

$ 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
}
于 2015-01-27T07:26:37.823 回答
0

这与 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;
于 2016-03-05T07:56:53.253 回答
-5
cat file_name.txt | sed 1d | sort 

这将做你想要的。

于 2016-03-09T12:22:07.103 回答