如何很好地对齐显示表格

如何很好地对齐显示表格

我正在尝试创建一个充当 ps 命令的脚本,并使用我想要显示的它自己的属性。假设进程在 ps 命令中是这样的:

sas 24431     1  0 Oct10 ?        00:51:08 /usr/lib/jvm/java-1.7.0-oracle-1.7.0.25.x86_64/jre/bin/java -Denv=DEV -Dapp.name=myApp -Xms512m -Xmx1g -Dlog.dir=/apps/java/logs

我想显示如下:

UID  PID    APPNAME
sas  24431  -Dapp.name=myApp
sas  24432  -Dapp.name=myApp2
sas  24433  -Dapp.name=myApp3

笔记:app.name属性是从 ps 命令中提取的命令参数

这是我的脚本:

echo -e "PID\tUSERID\t\tAPPNAME"
ps -u $USER -f |grep "java"|grep -v "grep"|
while read LINE 
do 
  #Get pid from the line
  PID=$(cut -d" " -f2 <<< $LINE);
  #Get parameter value called "-Dapp.name or -DprojectName" 
  #from the ps command for the process
  APPNAME=$(ps -f $PID | awk 'BEGIN {RS=" "}; /-Dapp.name|-DprojectName/');
  USERID=$(cut -d" " -f1 <<< $LINE);

 echo -e $PID"\t"$USERID"\t"$APPNAME;
done;

现在它按照我想要的方式工作。但有时对齐方式会被搞砸。另外这个脚本可以优化为一行命令吗?

任何帮助,将不胜感激。

答案1

对于通用表格对齐,您需要该column实用程序。

例如:

(
 printf 'PID\tUSER\tAPPNAME\n'
 printf '%s\t%s\t%s\n' "1" "john" "foo bar"
 printf '%s\t%s\t%s\n' "12345678" "someone_with_a_long_name" "pop tart"
) | column -t -s $'\t'

结果是:

PID       USER                      APPNAME
1         john                      foo bar
12345678  someone_with_a_long_name  pop tart

答案2

另外这个脚本可以优化为一行命令吗?

我会考虑使用-o命令选项ps来输出(尽可能)仅感兴趣的字段,然后进行后处理以匹配java您需要的进程和特定命令参数 - 类似于

ps -u $USER -o uname=,pid=,args= | 
  gawk -vOFS='\t' '/java/ {print $1,$2,substr($0,match($0,"-D(app[.]name)|(projectName)[^[:space:]]*"),RLENGTH)}'

或者也许是这样的perl免责声明:我的 Perl 知识很粗略

ps -u $USER -o uname=,pid=,args= | 
  perl -anle 'print join "\t", @F[0], @F[1], grep /-D(app[.]name)|(projectName)/,@F if /java/'

答案3

这是使用以下输出格式的另一个ps

#!/usr/bin/sh -f
printf '%-8.7s%-8s%s\n' $(
     ps -o uname=UID,pid=PID,args=APPNAME | 
     sed -n '1p;s/\( [0-9]* \).*\(-Dapp.name=[^ ]*\).*/\1\2/p'
)

根据其格式字符串,每 3 个参数printf将打印:

  1. 右侧第一个空格填充为 8 个字符的标准制表符宽度,并被截断为最多 7 个字符。
  2. 右侧第二个空格填充为 8 个字符的标准制表符宽度。
  3. 然后第三个后面是\neline。

命令替换是不是故意。请注意bang-line 中的-f以下内容sh- 它指定 shell 应该不是glob - 因此不存在根据 shell 特殊字符随机生成文件名的危险。命令替换将按$IFS默认值进行分割 - 空格、制表符、换行符。

在命令替换中ps打印 3 列 - 标题为用户识别码,PID, 和应用程序名称ps是 POSIX 指定的不是打印任何字段中的任何空格除外args=。所以前两列是$IFS安全的。尽管如此,为了将-Dapp.name字符串从args=字段中取出,必须对其进行处理。

所以sed过滤一下。在包含至少两个空格和字符串的行上-Dapp.name=它打印:

  1. 第一个空格序列,然后是零个或多个数字,然后是空格以及它前面的所有数字......
  2. 最后出现的包含字符串的序列-Dapp.name=后跟下一个出现的空格之前的所有字符。

sed的替换不会影响列标题 - 用 w/ 打印1p- 因为它们不包含-Dapp.name=细绳。所有其他行都将从输出中删除。

printf应用到sed的输出拆分后,$IFS您可以预期输出如下所示:

UID     PID     APPNAME
sas     24431   -Dapp.name=myApp
sas     24431   -Dapp.name=myApp
sas     24431   -Dapp.name=myApp
sas     24431   -Dapp.name=myApp
sas     24431   -Dapp.name=myApp

不过,在我看来,这种sed说法会更好一些:

sed -n '1p;s/\( [0-9]* \).*-Dapp.name=\([^ ]*\).*/\1\2/p'

基本上是一样的,只是去掉了-Dapp.name=部分,\2所以它打印起来像......

UID     PID     APPNAME
sas     24431   myApp
sas     24431   myApp
sas     24431   myApp

因为,既然是仅有的打印包含以下内容的行-Dapp.name=无论如何,顺序,包括它只是一种混乱,否则可以被认为是理所当然的。

相关内容