使用uniq -c时如何访问前缀

时间:2017-03-26 12:43:16

标签: dash-shell

我的程序遇到了问题。我有一个文件列表,我使用此代码对它们进行排序,以找出列表中最常用的10种文件类型。

find $DIR -type f | file -b $SAVEFILES | cut -c1-40 | sort -n | uniq -c | sort -nr | head -10 

我的输出看起来像这样

    168 HTML document, ASCII text
    114 C source, ASCII text
    102 ASCII text
     33 ASCII text, with very long lines
     30 HTML document, UTF-8 Unicode text, with 
     26 HTML document, ASCII text, with very lon
     21 C source, UTF-8 Unicode text
     20 LaTeX document, UTF-8 Unicode text, with
     15 SVG Scalable Vector Graphics image
     12 LaTeX document, ASCII text, with very lo

我想要做的是在文件类型之前访问值并替换它们#。我可以用for循环来表达,但首先我以某种方式访问​​它们。

预期的输出是这样的:

   __HTML document, ASCII text               : ################
   __C source, ASCII text                    : ###########
   __ASCII text                              : ##########
   __ASCII text, with very long lines        : ########
   __HTML document, UTF-8 Unicode text, with : #######
   __HTML document, ASCII text, with very lon: ####
   __C source, UTF-8 Unicode text            : #### 
   __LaTeX document, UTF-8 Unicode text, with: ###
   __SVG Scalable Vector Graphics image      : #
   __LaTeX document, ASCII text, with very lo: #

编辑:#不代表我的例子中的exect数字。第一行应该有168#,第二行应该有114#,等等

3 个答案:

答案 0 :(得分:1)

附加:

| while read -r n text; do printf "__%s%$((48-${#text}))s: " "$text"; for ((i=0;i<$n;i++)); do printf "%s" "#"; done; echo; done

根据您的需要更改48

输入时输出:

__HTML document, ASCII text                       : ########################################################################################################################################################################
__C source, ASCII text                            : ##################################################################################################################
__ASCII text                                      : ######################################################################################################
__ASCII text, with very long lines                : #################################
__HTML document, UTF-8 Unicode text, with         : ##############################
__HTML document, ASCII text, with very lon        : ##########################
__C source, UTF-8 Unicode text                    : #####################
__LaTeX document, UTF-8 Unicode text, with        : ####################
__SVG Scalable Vector Graphics image              : ###############
__LaTeX document, ASCII text, with very lo        : ############

答案 1 :(得分:1)

shell循环永远不是操作文本的正确方法,请参阅why-is-using-a-shell-loop-to-process-text-considered-bad-practice

您可以使用此awk命令执行您要求的操作:

$ awk '{printf "%-40s: %s\n", substr($0,9), gensub(/ /,"#","g",sprintf("%*s",$1,""))}' file
HTML document, ASCII text               : ########################################################################################################################################################################
C source, ASCII text                    : ##################################################################################################################
ASCII text                              : ######################################################################################################
ASCII text, with very long lines        : #################################
HTML document, UTF-8 Unicode text, with : ##############################
HTML document, ASCII text, with very lon: ##########################
C source, UTF-8 Unicode text            : #####################
LaTeX document, UTF-8 Unicode text, with: ####################
SVG Scalable Vector Graphics image      : ###############
LaTeX document, ASCII text, with very lo: ############

但这样做的正确方法是摆脱cut上的所有内容,并执行以下操作:

find "$DIR" -type f | file -b "$SAVEFILES" |
awk '
{ types[substr($0,1,40)]++ }
END {
    PROCINFO["sorted_in"] = "@ind_num_desc"
    for (type in types) {
        printf "%-*s: %s\n", 40, type, gensub(/ /,"#","g",sprintf("%*s",cnt[type],""))
        if (++cnt == 10) {
            break
        }
    }
}
'

以上使用GNU awk for sorted_in和gensub()以及第二个是未经测试的,因为你只提供了最后一部分的样本输入,打印了&#34;#&#34; s

答案 2 :(得分:0)

perl方法,添加:

| perl -lpE 's/\s*(\d+)\s(.*)/sprintf "__%-40s: %s", $2, "#"x$1/e'

输出

__HTML document, ASCII text               : ########################################################################################################################################################################
__C source, ASCII text                    : ##################################################################################################################
__ASCII text                              : ######################################################################################################
__ASCII text, with very long lines        : #################################
__HTML document, UTF-8 Unicode text, with : ##############################
__HTML document, ASCII text, with very lon: ##########################
__C source, UTF-8 Unicode text            : #####################
__LaTeX document, UTF-8 Unicode text, with: ####################
__SVG Scalable Vector Graphics image      : ###############
__LaTeX document, ASCII text, with very lo: ############

按照@ Ed的方法,只使用perl

find "$DIR" -type f | file -b "$SAVEFILES" |\
  perl -lnE '$s{substr$_,0,40}++;}{printf"__%-40s: %s\n",$_,"#"x$s{$_}for(splice@{[sort{$s{$b}<=>$s{$a}}keys%s]},0,9)'

可读:

perl -lnE '
$seen{ substr $_,0,40 }++;
END {
   printf"__%-40s: %s\n", $_, "#" x $seen{$_}
      for( splice @{[sort { $seen{$b} <=> $seen{$a} } keys %seen]},0,9 )
}'

Ps:请注意,文件工具只会测试$SAVEFILES中的文件,因此find ... | file -b $SAVEFILES毫无意义