如何使用格式设置 awk 和 printf 列并包括第 9 个之后的所有列

如何使用格式设置 awk 和 printf 列并包括第 9 个之后的所有列

我有下面的脚本使用 printf 进行格式化来打印从第一列到第九列的所有指定列,但是我想打印第九列之后的任何列,并且我不确定如何执行此操作

pwd=`pwd`
#Megabytes
max_size_1=`ls -ltr "$pwd" | grep -v "total" | awk '{print $1}' | sort -n | tail -1 | wc -m`
max_size_2=`ls -ltr "$pwd" | grep -v "total" | awk '{print $2}' | sort -n | tail -1 | wc -m`
max_size_3=`ls -ltr "$pwd" | grep -v "total" | awk '{print $3}' | sort -n | tail -1 | wc -m`
max_size_4=`ls -ltr "$pwd" | grep -v "total" | awk '{print $4}' | sort -n | tail -1 | wc -m`
max_size_5=`ls -ltr "$pwd" | grep -v "total" | awk '{$5=sprintf("%.0f M", $5/1024^2)} 1' | awk '{print $5}' | sort -n | tail -1 | wc -m`


ls -ltr "$pwd" | grep -v "total" | awk '{$5=sprintf("%.0f M", $5/1024^2)} 1' | eval "awk '{printf \"%$max_size_1-s %$max_size_2-s %$max_size_3-s %$max_size_4-s %$max_size_5-s %-3s %-3s %-3s %-6s\\n\", \$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8, \$9}'"

输出是:

-rwxr-xr-x  1  informix  informix  0  M   Mar 1   13:45 
-rwxr-xr-x  1  informix  informix  0  M   Mar 1   13:45 
-rwxr-xr-x  1  informix  informix  0  M   Mar 1   13:46 
-rwxr-xr-x  1  informix  informix  0  M   Mar 9   10:51 
-rw-r-----  1  informix  informix  0  M   Mar 9   12:36 
-rwxrwxrwx  1  informix  informix  0  M   Mar 9   13:01

我想要什么:

-rwxr-xr-x  1  informix  informix  0  M   Mar 1   13:45 ls-ltrg
-rwxr-xr-x  1  informix  informix  0  M   Mar 1   13:45 ls-ltrk
-rwxr-xr-x  1  informix  informix  0  M   Mar 1   13:46 ls-ltrb
-rwxr-xr-x  1  informix  informix  0  M   Mar 9   10:51 ls-ltrm
-rw-r-----  1  informix  informix  0  M   Mar 9   12:36 split word
-rwxrwxrwx  1  informix  informix  0  M   Mar 9   13:01 test.sh

它应该打印九个偶数文件或之后分割的名称之后的所有列。

答案1

我发现这是一个有趣的问题,主要是作为学习 awk 的机会。

解析ls稳健地是棘手的并且不推荐,所以我不会在这里详细介绍这些细节。如果您的文件名从不包含任何换行符,那么您可以使用以下 awk 脚本来完成您在单独的部分中所做的所有工作:

  • 找出“总计”行
  • 获取每个字段的长度
  • 动态格式化列

...所有这些都无需多次调用 ls、grep、awk、sort、tail 和 wc,无需使用eval.

由于默认ls列出当前目录 ( ),我也删除了它。pwd

一些随机笔记:

  • 我第一次使用时awk没有初始化i为零,所以我在 BEGIN 块中强制它为零

  • grep -v total部分发生在一行:/^total / { next; }

  • 实际的解决你的实际的问题是在for我们将文件名信息合并到第 9 列 .. NF 的循环中。

  • 格式分为两部分:forEND 块中的第一个循环确定我们需要的宽度;第二个for循环使用*格式说明符来完成实际工作——通过在实际值之前传递所需的宽度。

这是生成的脚本/代码:

ls -ltr | awk '
        BEGIN {
                i=0;
        }

        /^total / { next; }
        {
                perms[i]=$1
                links[i]=$2
                owner[i]=$3
                group[i]=$4
                $5=sprintf("%.0f M", $5/1024^2)
                size[i]=$5
                date[i]=$6 " " $7 " " $8
                for(x=9; x <= NF; x++) name[i] = name[i] " " $x
                i++
        }

        END {
                for(j=0;j<i;j++) {
                        if (length(perms[j]) > maxperms) maxperms = length(perms[j])
                        if (length(links[j]) > maxlinks) maxlinks = length(links[j])
                        if (length(owner[j]) > maxowner) maxowner = length(owner[j])
                        if (length(group[j]) > maxgroup) maxgroup = length(group[j])
                        if (length(size[j]) > maxsize) maxsize = length(size[j])
                }
                for(j=0;j<i;j++) {
                        printf "%-*s %-*s %-*s %-*s %-*s %s %s\n",
                                maxperms, perms[j],
                                maxlinks, links[j],
                                maxowner, owner[j],
                                maxgroup, group[j],
                                maxsize, size[j],
                                date[j],
                                name[j]
                }
        }
        '

非常感谢 G-Man,他提供了现成的备忘单供我使用awk 的动态列格式

相关内容