我正在尝试创建一个充当 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
将打印:
- 右侧第一个空格填充为 8 个字符的标准制表符宽度,并被截断为最多 7 个字符。
- 右侧第二个空格填充为 8 个字符的标准制表符宽度。
- 然后第三个后面是
\n
eline。
命令替换是不是引故意。请注意bang-line 中的-f
以下内容sh
- 它指定 shell 应该不是glob - 因此不存在根据 shell 特殊字符随机生成文件名的危险。命令替换将按$IFS
默认值进行分割 - 空格、制表符、换行符。
在命令替换中ps
打印 3 列 - 标题为用户识别码,PID, 和应用程序名称。ps
是 POSIX 指定的不是打印任何字段中的任何空格除外场args=
。所以前两列是$IFS
安全的。尽管如此,为了将-Dapp.name
字符串从args=
字段中取出,必须对其进行处理。
所以sed
过滤一下。在包含至少两个空格和字符串的行上-Dapp.name=它打印:
- 第一个空格序列,然后是零个或多个数字,然后是空格以及它前面的所有数字......
- 最后出现的包含字符串的序列-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=无论如何,顺序,包括它只是一种混乱,否则可以被认为是理所当然的。