编辑管道中的输出

Editing the output in a pipeline

我在编写 bash 脚本时遇到问题

cutfiles=`find $DIR -type f |
   file -b $SAVEFILES |
   cut -c1-40 |
   sort -n | 
   uniq -c | 
   sort -nr | 
   head -10 | 
   while read -r n text; do 
      printf "  %s...%$((40-${#text}))s: " "$text"
      for ((i=0;i<$n;i++)); do 
         printf "%s" "#"
      done
      echo
   done`

输出如下所示:

  ASCII text...                           : #######
  empty...                                : ####
  Bourne-Again shell script, ASCII text...: ##
  PDF document, version 1.4...            : #

我想做的是仅在文件类型超过 40 时才放置点,但并非总是如此。示例:

  ASCII text                              : #######
  empty                                   : ####
  Bourne-Again shell script, ASCII text...: ##
  PDF document, version 1.4               : #

有办法吗?

你可以使用 awk(应该比 bash 更快更便携):

filter()
{
    awk -F:    '{
        if(length()>40) printf "%.37s...:%s\n",,; else printf "%-40s:%s\n", ,; 
    }'
}
cat |  filter <<EOF
ASCII text                              : #######
empty                                   : ####
Bourne-Again shell script, ASCII text Lorem Ipsum: ##
PDF document, version 1.4               : #
EOF

输出:

ASCII text                              : #######
empty                                   : ####
Bourne-Again shell script, ASCII text...: ##
PDF document, version 1.4               : #

@PSkocik的awk解决方案很好
只是为了记录,你可以在没有 awk 的情况下做事(更慢)。

当字符串超过 40 位时,如果你想替换第 37 位之后的所有内容,你可以使用

sed 's/\(.\{37\}\).\{3\}.\+/.../' <<< "$text"

题外话:
你可以替换

  for ((i=0;i<$n;i++)); do 
     printf "%s" "#"
  done
  echo

   printf "%*.*s\n" $n $n '#' | tr ' '  '#'

编辑:
请注意,我的解决方案无法删除 cut,因为字符串的差异可能在第 40 个位置之后,并且您希望在输出中包含 uniq 行。只有第 38 个位置不同时,您会得到不同的输出行,因此最好将 cut 命令替换为 sed 命令。