Bash排序命令不正确排序彩色输出

问题描述:

在bash中使用/bin/sort我发现,输出通常是不正确的排序,当它来自彩色输入。Bash排序命令不正确排序彩色输出

例如,在包含以下内容的目录:

$ ls 
dir1   (directory, printed in blue) 
dir2   (directory, printed in blue) 
dir3   (directory, printed in blue) 
afile   (file, printed in white) 
file1   (file, printed in white) 
file2   (file, printed in white) 
file3   (file, printed in white) 

我希望ls | sort排序afile,再dir1,等等。相反,我得到:

$ ls | sort 
dir2 
dir3 
dir1 
afile 
file1 
file2 
file3 

我已经试过相当sort(-d,-g,-h,-n)的一些选项无济于事。

我已经能够解决这个问题的唯一办法是通过明确转向ls关闭的色彩输出:

$ ls --color=never | sort 
afile 
dir1 
dir2 
dir3 
file1 
file2 
file3 

但是,这感觉就像一个变通办法,而不是解决问题的办法。我一直认为必须有办法在最终输出中保留颜色,只适用于不关闭颜色的情况(例如对于不支持颜色禁用的ls以外的命令)。

一种力如何排序以仅对打印字符(即文件和目录名称)起作用?我有兴趣了解如何在事实之后彻底删除颜色输出(我已尝试strings,但获取蓝色文本的颜色说明符[01;34m),并且特别关注是否可以在排序后保留颜色输出。

+2

当输出到管道'ls'应该是默认禁用颜色。如果没有发生这种情况,那意味着您可能不小心使用“--color = always”启用了颜色,而不是仅使用“--color”。 – 2015-04-01 20:04:55

+2

使用'\ ls | sort'为'ls'禁用别名。 – Cyrus 2015-04-01 20:06:17

+0

它应该足够使用'--color = auto',对吧?当写入管道时,它会抑制颜色,并且您不必摆弄这些选项。 [编辑:我看到@Etan也是这么说的。] – alexis 2015-04-01 20:07:04

文本通过添加\x1b[...m形式的ANSI颜色序列进行着色,其中...被替换为一个或多个用分号分隔的数字,该数字描述样式。为了对文本进行排序,您需要忽略整个颜色序列,这远远超出了标准语言环境排序规则定义的功能。

如果彩色输出是由像ls这样的程序生成的,它可以独立地为每一行着色,您可以使用sed创建一个排序键 - 删除了颜色序列的行 - 然后是完全着色的行。

这是一个简单的解决方案,要求TAB不存在于任何行中。 (此外,还要求有在任何条目不换行,但是这是需要的事实,条目是各个行,这是一个基本的前提使用sort。)

ls -U --color=always | # Sample data input 
sed 'h;s/\x1b[[0-9;]*m//g;G;s/\n/\t/' | # Insert the sort key 
sort |     # Sort the result 
cut -f2-    # Remove the sort key 

sed命令的说明:

h     Copy the line to the hold space 
s/\x1b[[0-9;]*m//g Remove all colour sequences 
G     Append a newline and the contents of the hold space 
s/\n/\t/   Change the newline to a tab 

注意:使用反斜杠比sed的模式\n其他和替换是GNU扩展,可能在其他SED实现也可以,但不是POSIX标准要求。对于Posix标准sed,您需要分别用二进制ESC和TAB替换\x1b\t

首先,你为什么需要sortls有一吨订购选项内置?也许你可以通过阅读ls的手册来解决你的问题。

但是假设你确实需要不区分颜色的排序:你可以告诉sort在指定数量的字符之后开始排序,这并不是你所需要的,但它总比没有好。我没有ls的版本,所以我无法确认,但简单的彩色文本通常是以五个字符的顺序激活的。例如,蓝色是^[[34m。那么,告诉sort开始与第六个字符排序:

ls | sort -k 1.6 

但对于普通文件?他们可能没有获得彩色前缀,因此上述内容将会失败,除非您将其过滤为在黑色线条前添加相同数量的字符。为了对称,您可以简单地添加黑色(^[[00m,使其成为五个字符)。

ls | perl -pe '{ s/^/\e\[00m/ unless /^\e\[/ }' | sort -k 1.6