首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >知道为什么排序实用程序会给我不正确的结果吗?

知道为什么排序实用程序会给我不正确的结果吗?
EN

Stack Overflow用户
提问于 2017-03-19 20:30:25
回答 3查看 114关注 0票数 1

编辑:为了清楚起见,我们从一个执行如下的for循环中获得了STDOUT

代码语言:javascript
复制
for (( i=1; i<="$FILE_AMOUNT"; i++ )); do
    MY_FILE=`find $DIR -type f | head -$i | tail -1`
    FILE_TYPE=`file -b "$MY_FILE"
    FILE_TYPE_COUNT=`echo $FILE_TYPE" | sort | uniq -c`
    echo "$FILE_TYPE_COUNT"
done

因此,我们的STDOUT基本上是从逐个打印的文件实用程序中输出的,而不是实际上是我们可以复制的字符串集--这很可能是所有问题背后的核心。

`

所以有个泡菜我绝对不能把头绕着。

基本上,我正在创建一个print脚本,它将打印出我们目录中的各种文件类型。但是,由于一些奇怪的原因,当我试图在输出中使用uniq时,它就不能工作了。这是我的输出

代码语言:javascript
复制
POSIX shell script, ASCII text executable
ASCII text
Bourne-Again shell script, ASCII text executable
UTF-8 Unicode text, with overstriking
Bourne-Again shell script, ASCII text executable

似乎很清楚,但是当我使用

代码语言:javascript
复制
FILE_TYPE_COUNT=`echo "$FILE_TYPE" | sort | uniq -c`

这是它打印的结果

代码语言:javascript
复制
  1 POSIX shell script, ASCII text executable
  1 ASCII text
  1 Bourne-Again shell script, ASCII text executable
  1 UTF-8 Unicode text, with overstriking
  1 Bourne-Again shell script, ASCII text executable

显然应该是

代码语言:javascript
复制
  1 POSIX shell script, ASCII text executable
  1 ASCII text
  2 Bourne-Again shell script, ASCII text executable
  1 UTF-8 Unicode text, with overstriking

知道我做错什么了吗?

显然,uniq认为行没有什么不同,但我认为这是排序的错误,因为它不能对我的STDOUT进行排序。那么如何正确地对列表进行排序,ALPHABETICALlY呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-03-19 21:01:41

您的方法似乎过于复杂,请尝试如下:

代码语言:javascript
复制
find $DIR -type f -exec file -b -- {} \; | sort | uniq -c

如果您不熟悉-exec,它会执行给定的命令,在我们的例子中是file -b -- {},每个文件执行一次。位置保持器{}被替换为当前正在处理的文件的路径。

为什么你的方法行不通:

在for循环中执行此echo $FILE_TYPE" | sort | uniq -c,此时$FILE_TYPE只包含一个文件的文件类型。您需要将sort | uniq -c移出循环。

我调整了您的代码,使其工作:

代码语言:javascript
复制
declare -a TYPES=()
for (( i=1; i<="$FILE_AMOUNT"; i++ )); do
    MY_FILE=`find a/ -type f | head -$i | tail -1`
    FILE_TYPE=`file -b "$MY_FILE"`
    TYPES+=("$FILE_TYPE") # add type of current file to TYPES array
done

# TYPES now contains the types of all files and we can now count them
printf "%s\n" "${TYPES[@]}" | sort | uniq -c
票数 4
EN

Stack Overflow用户

发布于 2017-03-19 21:09:22

您所看到的问题是,您正在为循环的每一次迭代排序一组项。

您需要对循环的整个输出进行排序。

您的(语法固定的)脚本:

代码语言:javascript
复制
for (( i=1; i<="$FILE_AMOUNT"; i++ )); do
    MY_FILE=`find $DIR -type f | head -$i | tail -1`
    FILE_TYPE=`file -b "$MY_FILE"`
    FILE_TYPE_COUNT=`echo "$FILE_TYPE" | sort | uniq -c`
    echo "$FILE_TYPE_COUNT"
done

经适当调整后,可正常工作:

代码语言:javascript
复制
for (( i=1; i<="$FILE_AMOUNT"; i++ )); do
    MY_FILE=`find $DIR -type f | head -$i | tail -1`
    file -b "$MY_FILE"
done | sort | uniq -c

优化过一次:

代码语言:javascript
复制
for FILE in $(find $DIR -type f); do
    file -b "$FILE"
done | sort | uniq -c

优化了两次(见@P.Gerber的回答):

代码语言:javascript
复制
find $DIR -type f -exec file -b -- {} \; | sort | uniq -c

你原来的剧本效率太低了。

关于效率和运作的说明:

  • ${FILE_AMOUNT}必须正确地遍历整个数据集。
  • 您正在运行find,它返回整个数据集,然后丢弃您不感兴趣的所有内容,每次迭代
  • 在每次迭代中,您都在大小为1的数据集中运行sortuniq
  • 由于您正在不断地重新计算数据集,如果它在脚本执行过程中发生了变化(例如:创建/删除了文件/目录),则结果将变得无效。
  • 记住,每次启动新程序时,都会付出性能上的损失--这是因为您一直在计算数据集,然后丢弃“您不想要的所有东西”这一事实加剧了这种情况。
票数 1
EN

Stack Overflow用户

发布于 2017-03-19 22:01:26

除了这里的其他好解决方案之外,一定要理解您正在使用的排序规则集。要检查当前的排序规则,可以执行以下操作:

代码语言:javascript
复制
echo anything | sort --debug

使用注释查看您的结果。考虑:

代码语言:javascript
复制
echo -e "a 2\na1" | sort --debug
sort: using ‘en_US.UTF-8’ sorting rules
a1
__
a 2
___

注意,规则集正在排序,可能有一个意外的结果。如果您正在寻找一个简单的字节比较,那么一定要将LC_ALL=C设置为:

代码语言:javascript
复制
LC_ALL=C sort

例如:

代码语言:javascript
复制
echo -e "a 2\na1" | LC_ALL=C sort --debug
sort: using simple byte comparison
a 2
___
a1
__

使用LC_ALL对于获得您期望的结果非常重要。最后,运行locale命令并读取手册页以获取特定于地区的信息。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42891893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档