awk - Bash/GitBash AWK 通过列名而不是列号获取列值(来自命令输出)
问题描述
我安装了最新的 GitBash 版本并且$BASH_VERSION
是4.4.23(1)
.
现在我得到这个命令的输出,ps aux
如下所示:
PID PPID PGID WINPID TTY UID STIME COMMAND
<4-DIGITS> <1-DIGIT> <4-DIGITS> <4-DIGITS> ? <5-DIGITS> <CURR_TIME> <COMMAND>
<4-DIGITS> <1-DIGIT> <4-DIGITS> <4-DIGITS> ? <5-DIGITS> <CURR_TIME> <COMMAND>
....
....
<4-DIGITS> <1-DIGIT> <4-DIGITS> <4-DIGITS> ? <5-DIGITS> <CURR_TIME> <COMMAND>
<4-DIGITS> <1-DIGIT> <4-DIGITS> <4-DIGITS> ? <5-DIGITS> <CURR_TIME> <COMMAND>
从这个输出中,我希望能够通过仅指定列名称(也可以是多个列)来提取特定的列值,而不是每次从左到右计算列号的列。
我有这个命令,但它只适用于文件,但我希望它也适用于另一个命令的输出:
awk -vcol=<COL_NAME> '(NR==1){colnum=-1;for(i=1;i<=NF;i++)if($(i)==col)colnum=i;}{print $(colnum)}'
如何使这项工作用于过滤先前命令的输出,例如ps aux | awk <COLUMN_NAME=WINPID>
?
解决方案
假设:
ps
输出字段不包含空格(例如,下面的条目STIME
看起来不像Sep 27
)- 列名匹配区分大小写(可以通过添加
tolower()
调用来更改)
示例输入文件:
$ cat ps.out
PID PPID PGID WINPID TTY UID STIME COMMAND
<4-DIGITS1> <1-DIGIT1> <4-DIGITS1> <4-DIGITS1> ? <5-DIGITS1> <CURR_TIME1> <COMMAND1>
<4-DIGITS2> <1-DIGIT2> <4-DIGITS2> <4-DIGITS2> ? <5-DIGITS2> <CURR_TIME2> <COMMAND2>
<4-DIGITS3> <1-DIGIT3> <4-DIGITS3> <4-DIGITS3> ? <5-DIGITS3> <CURR_TIME3> <COMMAND3>
<4-DIGITS4> <1-DIGIT4> <4-DIGITS4> <4-DIGITS4> ? <5-DIGITS4> <CURR_TIME4> <COMMAND4>
一个想法使用awk
:
$ columns='WINPID'
$ awk -v cols="${columns}" '
BEGIN { n=split(cols,arr,",") # parse list of column names
for (i=1;i<=n;i++)
headers[arr[i]] # convert to associative array
}
FNR==1 { for (i=1;i<=NF;i++) # for each field (aka column) header ...
if ($i in headers) # if it is in headers[] then ...
fields[i] # keep track of the associated field #
}
{ pfx=""
for (i=1;i<=NF;i++) { # for each input field # ...
if (i in fields) { # if it is in fields[] then ...
printf "%s%s", pfx, $i # print the field (aka column)
pfx=OFS
}
}
printf "\n" # terminate the line
}
' ps.out
这会产生:
WINPID
<4-DIGITS1>
<4-DIGITS2>
<4-DIGITS3>
<4-DIGITS4>
columns='WINPID,UID'
我们得到:
WINPID UID
<4-DIGITS1> <5-DIGITS1>
<4-DIGITS2> <5-DIGITS2>
<4-DIGITS3> <5-DIGITS3>
<4-DIGITS4> <5-DIGITS4>
注意: OP 可以修改printf
格式以根据需要调整输出
要将awk
脚本直接应用于ps
(通过模拟cat ps.out
)的输出:
$ columns='PID,STIME,COMMAND'
$ cat ps.out | awk -v cols="${columns}" '
BEGIN { n=split(cols,arr,",")
for (i=1;i<=n;i++)
headers[arr[i]]
}
FNR==1 { for (i=1;i<=NF;i++)
if ($i in headers)
fields[i]
}
{ pfx=""
for (i=1;i<=NF;i++) {
if (i in fields) {
printf "%s%s", pfx, $i
pfx=OFS
}
}
printf "\n"
}
'
这会产生:
PID STIME COMMAND
<4-DIGITS1> <CURR_TIME1> <COMMAND1>
<4-DIGITS2> <CURR_TIME2> <COMMAND2>
<4-DIGITS3> <CURR_TIME3> <COMMAND3>
<4-DIGITS4> <CURR_TIME4> <COMMAND4>