在awk中使用basename还是endwith?

时间:2012-02-24 03:17:28

标签: bash awk

我正在使用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的内容?

6 个答案:

答案 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}')