【问题标题】:How to access the prefix when using uniq -c使用 uniq -c 时如何访问前缀
【发布时间】:2017-08-19 02:59:33
【问题描述】:

我在我的程序中遇到了问题。我有一个文件列表,我使用此代码对它们进行排序,以找出列表中最常见的 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: #

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

【问题讨论】:

  • 查看上一个问题的答案:Calling function in awk
  • 好吧,我试过了,但没用
  • 为什么要删除 bash 标签?
  • 您最近的编辑删除了预期的输出,并使答案似乎无法产生现在听起来像您要求的问题。我已经恢复了它。请受邀进一步完善您的问题,但不要让您更难理解您在寻找什么。

标签: dash-shell


【解决方案1】:

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 毫无意义

【讨论】:

    【解决方案2】:

    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 来处理 sorted_in 和 gensub() 并且第二个是未经测试的,因为你只为最后一部分提供了示例输入,打印了“#”s

    【讨论】:

      【解决方案3】:

      附加这个:

      | 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 文档,ASCII 文本:########################################### ################################################# ################################################# ######################## __C 源代码,ASCII 文本:########################################### ################################################# #################### __ASCII 文本:############################################### ################################################# ##### __ASCII 文本,行很长:################################ __HTML 文档,UTF-8 Unicode 文本,带有:############################# __HTML 文档,ASCII 文本,很长:########################## __C 源代码,UTF-8 Unicode 文本:#################### __LaTeX 文档,UTF-8 Unicode 文本,带有:#################### __SVG 可缩放矢量图形图像:################ __LaTeX 文档,ASCII 文本,非常低:############

      【讨论】:

      • 重要提示:我已将 &lt;= 替换为 = 以修复错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-09
      相关资源
      最近更新 更多