1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
| 7.1 'sort': Sort text files ===========================
sort命令用于排序、合并或比较给定文件(可给定多个)的所有行,如果没有给 定输入文件或输入文件为"-",则读取标准输入。默认情况下,sort将操作结 果打印在标准输出中。语法:
sort [OPTION]... [FILE]...
sort有3种操作模式:排序(默认)、合并以及检查是否已经排过序。使用以下3 个选项改变操作模式:
'-c' '--check' '--check=diagnose-first' 检查给定文件是否已经排序过:如果检测出未排序,将输出诊断信息并以 状态码1退出,该诊断信息中包含第一个乱序的行。否则以成功状态退出。 最多只能给定一个检测文件。
'-C' '--check=quiet' '--check=silent' 它类似于"-c",但不会输出诊断信息。如果文件已排序,则以成功状态退 出,否则以状态码1退出。最多只能给定一个文件。
'-m' '--merge' 合并多个文件,每个输入文件必须已经排序。合并时将根据已排序的结果 合并为各个组。sort一般都用来排序,但仍然提供合并功能,因为它的合 并速度很快。
sort排序规则为:按照命令行中给定的字段顺序对给定的字段进行排序,排序时 根据为每个字段分配的排序选项进行排序,直到发现不同的排序选项或者排序列 结束。如果没有给定排序key(注:key即为-k指定的值),则对整行进行排序。最 后,如果所有给定的key的比较结果都相等时,将对整行进行完全默认的排序 (注:即以字母升序排序),但"-r"可以改变这次的升、降序结果。这次排序称为 "最后的排序"。使用"-s"选项可以禁止"最后的排序",使得那些排序结果相同的 行保留最初的相对顺序。"-u"选项同样也会禁止"最后的排序"。
除非明确指定,否则所有的比较都按照"LC_COLLATE"指定的字符集的排序规则进 行排序。
退出状态码:
0 没有任何错误发生时 1 如果"-c"或"-C"检测发现输入数据未排序时 2 发生了错误时
如果设置了环境变量"TMPDIR",sort将使用它作为临时目录而不是默认的"/tmp"。 "-T"选项将覆盖该环境变量设置的值。
以下选项影响排序的输出结果。它们既可以指定为全局选项,也可以作为key的 一部分。如果未指定任何key,则全局选项将作用于整行,否则指定的key将继承 全局选项,除非key自身也指定了选项(注:自身指定了选项的key将覆盖全局选 项)。为了考虑可移植性,建议将全局选项指定在"-k"(或"--key")的前面。
'-b' '--ignore-leading-blanks' 忽略key的前导空白符号(包括空格、制表符)。不给定该选项时,空白符号 对"-k"选项指定字符位置有影响(注:例如"-k 2.2"指定的第2个字符可能是 空白)。
'-f' '--ignore-case' 将小写字符当作大写字符。例如,"b"和"B"是相等的。当和"-u"选项一起 使用时(注:重复的行只能输出一次),那些小写字符的等价行会被丢弃 (注:也就是说,输出的是大写字符行)。(目前没有任何方法可以抛弃大写 字符的等价行,即使使用"-r"也不行,因为在任何时候,"-r"选项都只是 反转最终的排序结果,不会影响排序过程)。
'-h' '--human-numeric-sort' '--sort=human-numeric' 对文件大小格式进行排序。首先对正负性排序(正数>0>负数),再对大小后 缀排序(0<k=K<M<G<T...),最后对数值排序。它不在乎转换精度是1000还是 1024,因为它总会自动不断扩大到最接近的后缀(注:例如999M和1G比较时 将以1000作为转换单位,1023M和1G比较时将以1024作为转换单位)。
'-M' '--month-sort' '--sort=month' 按字符格式的月份进行排序。 An initial string, consisting of any amount of blanks, followed by a month name abbreviation, is folded to UPPER case and compared in the order 'JAN' < 'FEB' < ... < 'DEC'. Invalid names compare low to valid names.
'-n' '--numeric-sort' '--sort=numeric' 按数值排序。空字符串""或"\0"被当作无。数值排序是精确排序,不会四舍五入 后排序。
( 注:数值排序和默认的排序规则所不同的是,当key中遇到非数学字符时, 如空白、字母、特殊字符等,将直接结束排序(在sort内部认为找不到匹配 值)。也就是说,"-k 2"和"-k 2n"不同,虽然这两个key都会扩展到行尾, 前者会从第二个字段一直按字符集顺序比较到行尾,而后者可能只对第2 字段匹配,因为第二字段和第三字段中间可能有特殊符号,导致数值排序 直接结束。
因此,对于"abc 100 200"这样的输入,指定"-k 2n"时,该key为"100 200", 但由于中间包含了空白,使得该key的排序在第二字段就结束。 如果是"abc 100\0200 200","-k 2n"在排序时,虽然看上去是100200,但 却只对100进行排序,也就是说,如果此时另有一行第2字段值为110,看上 去很大的100200将小于110。测试语句: echo -e "b 100:200 200\na 110 300" | tr ':' '\0'|sort -t ' ' -k2n -k1
因此,对于"-n"来说,它绝对不可能跨越key的边界。但默认的排序规则 会跨越key起作用。 )
'-r' '--reverse' 反转比较的结果,使得结果中更大的key更早出现。 (注:"-r"不会改变排序行为,而是将排序结束后的输出结果进行反转 处理,因此只影响排序结束后的输出结果)
'-k POS1[,POS2]' '--key=POS1[,POS2]' 指定排序的key,即每行排序的起始和终止字段(若省略POS2,则终止位置为 行尾)。
POS的格式为"F[.C][OPTS]",其中F表示字段的序号,C表示该字段中字符 的序号。字段和字符的位置都从1开始计算。如果POS2的字符位置指定为 0,则表示POS2字段中的最后一个字符。如果POS1中省略".C",则默认值 为1(字段的起始字符),如果POS2中省略".C",则默认值为0(字段的终止 字符)。OPTS为排序选项,这些选项将覆盖全局选项,使得该key可以按照 独立的排序选项进行排序。keys可以跨多个字段。 (注:OPTS指定在POS1和POS2的作用是一样的,因为一个"-k"指定一个key, 无论是POS1还是POS2中的OPTS都是对这个key有效,但"b"选项除外,见下文)
示例:为了排序第二个字段,使用"--key=2,2"(-k 2,2)。可使用"--debug" 选项帮助查看、分析和决定每行中被用于排序的字段。
'--debug' 显示每行中用于排序的部分。还会给出额外的信息。
'-o OUTPUT-FILE' '--output=OUTPUT-FILE' 将排序的输出结果写入到OUTPUT-FILE中。一般来说,sort在打开OUTPUT FILE前读取完所有输入,因此可以安全地将排序结果保存到输入文件中, 就像"sort -o file1 file1"和"cat file1 | sort -o file1"一样。但是, "-m"选项会在读取输入前先打开输出文件,因此下面的语句是不安全的 语句:"cat file1 | sort -m -o file1 -"。
'-s' '--stable' 禁止sort执行"最后的排序"。在没有指定字段选项或全局选项时,该选 项将不起作用,除非指定的是"-r"选项。 (注:最后的排序:在key的比较结果相同时,sort的最后手段是对整行 再进行一次完全默认的排序,即按照字母、升序对整行做最后排序。这 称为"最后的排序"。如果未指定任何选项,其本身就是完全默认的,因 此没必要再做最后的排序。如果指定的是"-r"选项,由于"-r"是对最终 结果进行反转排序,因此会影响这次的"最后的排序"的结果)
'-t SEPARATOR' '--field-separator=SEPARATOR' 当在每行中搜索key的时候,使用SEPARATOR字符作为字段的分隔符。默认 情况下,字段是由空白字符和非空白字符之间的空字符串分割而来的。
因此,如果输入行为" foo bar",默认将切分为两个字段" foo"和" bar", (注:空白和非空白字符之间的空字符为行开头和"oo"后的位置)。字段分 隔符不是分隔后字段中的内容,因此"sort -t ' '"对" foo bar"分隔时, 将分割为3个字段:空字段、"foo"和"bar"。但是,每个单独的字段都是扩 展到行结尾的,就像"-k 2",或像"-k 2,3"包含了范围的字段,它们都在扩 展的时候保留字段分隔符。 (注:以sort -t ' '为例,"-k 2"实际上表示的是"foo bar",它扩展到 行尾,且中间的字段分隔符被保留。而"-k 1,2"实际上表示的是" foo", 因为明确指定了这个key到第二个字段结束,但中间的字段分隔符仍保留) 如果要指定字段分隔符为空,则使用"\0",例如"sort -t '\0'"。
'--parallel=N' 设置sort运行的并行线程数为N。默认,N设置为可获得的cpu个数,但最大 限制为8,因为超过8之后带来的性能收益递减。
'-u' '--unique' 一般情况下,"-u"将仅输出排序后重复行的第一行。
该选项会禁止"最后的排序"(注:见前文译文)。
"sort -u"和"sort | uniq"是等价的,但扩展了更多选项后将可能不等价, 例如,"sort -n -u"只会检查数值部分的唯一性,但"sort -n | uniq"在 sort对行的数值排序后,uniq将检查整个行的唯一性。
'-z' '--zero-terminated' 使用"\0"分割每行而不是使用换行符。
"-k"指定的key后面可以指定"bfhgnr"等选项,这种情况下,该key将不会继承 全局选项。除了"b"选项,所有的选项都作用于整个key,无论该选项是写在POS1 还是POS2上。如果指定了"b"选项,它仅独立作用于POS1或POS2上,但如果继承 了全局的"-b",则会作用于整个key上。如果输入行中包含了前导空白字符, 且没有使用"-t"选项,"-k"通常会结合"-b"或某些隐含了忽略前导空白字符的 选项(ghn)一起使用,否则前导空白字符可能会导致划分的字段非常混乱。
如果POS中指定的字段或字符位置超出了行尾或字段,则该key为空。如果指定了 "-b"选项,".C"部分将从字段的第一个非空白字符开始计算。
以下是一些示例,用于说明不同选项的结合使用:
* 按数值排序,并降序(reverse)
sort -n -r
* 按字母排序,忽略第一和第二字段,且忽略第三字段的前导空白。此处 使用了单个key,该key从第三字段非空白字符开始,一直扩展到行的结尾。 这一整个key都采用字母排序。
sort -k 3b
* 对第二字段按数值排序,并通过指定第五字段的第3、4字符间按字母排序 来解除按数值排序的规则。使用":"作为字段分隔符。
sort -t : -k 2,2n -k 5.3,5.4
(注:任何时候,只想对某字段进行排序时,都建议明确指定其起始和结束位置)
注意,如果写的是"-k 2n"而不是"-k 2,2n",该key将从第二字段一直扩展 到行尾,这是主排序key,而副排序key"-k 5.3,5.4"在主排序key的排序基 础上再按照字母排序。绝大多数情况下,让key向后扩展一般不是所期望的 行为。
还需注意,"n"选项作用范围为第一个key。这等价于"-k 2n,2"或"-k 2n,2n"。 所有的修饰符,除了"-b",无论写在pos1还是pos2,都会作用于整个key。
( 注:由于n选项无法跨越key,因此上面即使写成了"-k 2n"也是等价的,但下 面两个命令则不一样:
sort -t : -k 2 -k 5.3,5.4n sort -t : -k 2,2 -k 5.3,5.4n
由于默认的字符集排序规则会跨越key,第一条命令中主key从第2字段开始, 直到行尾结束,于是会先对整个key按字符排序,然后在此基础上再对副key 按数值排序。 再如下面的例子:
sort -t : -k 5n -k 2
即使主key的字段在副key的字段后面,副key由于是做字符集排序,所以仍 会跨越主key。 )
* 对/etc/passwd文件的第5字段排序,并忽略前导空白。如果第5字段排序 结果相等,则进一步按数值对第3字段的uid进行排序。字段分隔符为":"。
sort -t : -k 5b,5 -k 3,3n /etc/passwd sort -t : -n -k 5b,5 -k 3,3 /etc/passwd sort -t : -b -k 5,5 -k 3,3n /etc/passwd
以上三个命令是等价的。第一个命令指定了第一个key的POS1要忽略前导 空白,且第二个key要按照数值排序。另外两个命令中,缺少选项的key将继 承全局选项。此处继承之所以能正确工作,是因为"-k 5b,5b"和"-k 5b,5"是 等价的。
* 对一系列日志文件进行排序,主排序key为IPv4,副排序key为时间戳。如果 两行的主、副key都完全一致,则按照文件被读取时的相对顺序输出。日志 文件包含的行格式大致如下:
4.150.156.3 - - [01/Apr/2004:06:31:51 +0000] message 1 211.24.3.231 - - [24/Apr/2004:20:17:39 +0000] message 2
使用单个空格可以精确分割这些字段。IPV4地址列按照字典顺序排序,例如 212.61.52.2小于212.129.233.201,因为61小于129。
sort -s -t ' ' -k 4.9n -k 4.5M -k 4.2n -k 4.14,4.21 file*.log | sort -s -t '.' -k 1,1n -k 2,2n -k 3,3n -k 4,4n
该示例无法仅使用一个sort语句实现,因为IPV4地址需要使用"."分隔,而 时间戳需要使用空格分隔。因此,使用两个sort语句:第一个sort语句按照 时间戳排序,第二个语句按照IPV4排序。第一个sort命令中使用"-k"将每个 字段进行隔离,先按照年排序,再按照月份排序,接着是日,最后对 "时:分:秒"排序。除了"时:分:秒"这个key,其余的key都没必要指定key的结 束位置,因为"n"和"M"选项作用范围不能跨域每个key的左边界。第二个sort 命令是对ipv4地址按照字典顺序排序的。第二个sort语句中使用了"-s"选项, 以防止主排序key的关系被副排序key破坏,第一个sort语句中使用"-s"选项是 为了保证两个sort语句在"-s"属性上的一致性。
(注:由于n选项无法跨越key边界和非数学字符,因此上面第二个sort命令和 下面的命令是等价的: sort -s -t '.' -n -k1 -k2 -k3 -k4)
|