编辑管道

时间:2017-04-09 06:53:44

标签: bash dash-shell

我在编写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               : #

有办法吗?

2 个答案:

答案 0 :(得分:1)

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

如果你想在第37个pos之后更换一个字符串超过40个pos时的所有内容,你可以使用

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

题外话:
你可以替换

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

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

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

答案 1 :(得分:0)

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

filter()
{
    awk -F:    '{
        if(length($1)>40) printf "%.37s...:%s\n",$1,$2; else printf "%-40s:%s\n", $1,$2; 
    }'
}
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               : #