我正在使用awk
按名称获取特定进程的pid
。
#!/bin/sh
for pid in $(ps | awk '$4 == "foo" { print $1 }')
do
i=1
echo "killing foo at pid $pid"
kill $pid && echo 'ok' || echo 'failed'
done
OSX上的ps
输出类似于:
$ ps
PID TTY TIME CMD
1858 ttys000 0:00.15 -bash
4148 ttys000 0:01.37 /a/b/c/foo
但是我的shell脚本仅在CMD
列中的进程正好为foo
(无绝对路径)时才有效。
我想我可以使用basename
,但如何从awk
调用它?
OR
在$4.endswith('foo')
中是否有类似awk
的内容?
答案 0 :(得分:7)
awk
可以使用正则表达式。所以,而不是$4 == "foo"
,你可以做类似的事情:
awk '$4 ~ /\/foo$/ { print $1 }'
正则表达式介于/
和/
之间。 \/foo$
说"反斜杠后跟foo然后结束字段。"在这种情况下,您的字段为/a/b/c/foo
,因此匹配。
答案 1 :(得分:3)
除了正则表达式,您还可以将字符串操作用作substr($4, length($4) - 2) == "foo"
。
答案 2 :(得分:3)
首先,您应该使用while read
结构而不是for
。使用for
循环,您必须等待$(...)
中的命令在for循环开始之前执行。另外,可以超出命令缓冲区。今天不是一个主要问题,但当你碰到它时,你永远不会得到任何出错的迹象:
ps | awk '$4 == "foo" { print $1 }' | while read pid
do
i=1
echo "killing foo at pid $pid"
kill $pid && echo 'ok' || echo 'failed'
done
与你的问题没什么关系,但我需要把它从你的胸口拿走。
现在回答你的问题:
awk
会自动循环,所以既然你正在使用awk
,那么为什么不让它为你工作呢?大多数awk
实现都有system
命令,因此您可以在kill
脚本内执行awk
。
另外,请查看man ps
并检查您的PS选项。大多数ps命令采用-o
选项,允许您指定要打印的字段。我的ps
命令(恰好在OS X上)允许您使用ucomm
,它只是没有目录或命令行参数的命令名称。听起来对你的情况有用。我将使用ps -opid, ucomm
,它只会为ps
命令打印两列:PID和命令名称sans目录和命令行参数:
$ ps -o pid,ucomm
PID UCOMM
1 launchd
10 kextd
11 UserEventAgent
12 mDNSResponder
13 opendirectoryd
14 notifyd
15 fseventsd
16 configd
17 diskarbitrationd
18 syslogd
(只有一个警告,看起来ucomm
会在第14或第16列删除。只是为了让你知道。
对于awk
,我们可以使用-v
参数来定义Awk变量。这在您编写shell脚本时非常有用,并且希望awk从命令参数中获取程序的名称。
在Awk中,如你所知,$ 1代表PID,$ 2代表命令sans目录或命令行参数。
我们可以使用$2 == command
过滤出命令为ps
的{{1}}命令中的所有行。这是foo
语句的快捷方式。
并且,if
的大多数实现都有一个awk
函数,可用于从system
脚本中运行kill
之类的命令。看起来我们几乎拥有所需的一切:
awk
这是一个很好的干净的一个班轮,但它不会检查系统命令的状态,也不会在它失败或你正在杀死什么命令和PID时回显。
好的事情是,Awk不仅仅是一个深奥的命令。它也是一种深奥的编程语言。我们可以测试ps -o pid,ucomm | awk -v command="foo" '$2 == command {system("kill " $1)}'
命令的返回并添加一些打印语句。我没有对此进行测试,但它应该非常接近:
system
ps -o pid,ucomm | awk -v command="foo" '$2 == command {
print "Killing " $2 " at PID " $1
if (system("kill " $1)) {
print "Failed to kill PID " $1
}
}'
可能必须是if
。
答案 3 :(得分:2)
对于条件,您可以使用
$4 ~ /\/foo$/
转换为“第4个字段匹配(转义)正斜杠,然后是行尾的'foo'。”
答案 4 :(得分:2)
看来你正试图杀死名为'foo'的所有进程,如何:
killall foo
答案 5 :(得分:0)
在查找pids时,您必须排除awk进程,否则可能会导致搜索进程失效。
kill $(ps -aef | awk -v program="mplayer" '$0 ~ program {if ($0 !~ "awk") print $2}')