プロセス名からプロセスIDとフルパスを取得する何か

前記事: 任意のプロセス名からそのプログラムの絶対パスを得る - 日々量産
一個の関数で済むようにシェルスクリプトで書き書き。
grep以外は馴染みがないLinux初心者なのでとても苦労しました。
(もしかしたらCentOS 6.0 x86_64以外では動作しないかもしれません)
もっとうまい方法があるような気がしてなりません。

#!/bin/sh

if [ $# -ne 1 ] ; then
        echo usage: $0 [VALUE]
        exit 1
fi

# プロセス名からプロセスID探索
pid(){
        PROGRAM=$1
        line=$2

        TEMP_PID=`echo $line | sed "s#.*/proc/\([0-9]\+\)/.\+#\1#" `;
        if [ "$line" != "$TEMP_PID" ] ; then
                PID=$TEMP_PID
        fi

        FULLPATH=`echo "$line" | awk '{printf \$12}'`

        if [ "${PROGRAM:0:1}" != "/" ]; then
                PROGRAM=/$PROGRAM
        fi

        if [ `echo $FULLPATH | grep "$PROGRAM\$"` ] ; then
                echo "$PID" "$FULLPATH"
        fi
}

getpid(){
        PROGRAM=$1;
        IFS=$'\n';

        for line in `ls -l /proc/*/exe 2>/dev/null`; do
                pid $PROGRAM $line
        done

        for line in `ls -l /proc/*/fd 2>/dev/null`; do
                pid $PROGRAM $line
        done
}

getpid $1

使い方

こんな感じに使えればーって思ってます

./pid.sh pid.sh | kill `awk '{print $1}'`

  • bash: kill: (28188) - そのようなプロセスはありません


同じプロセスが複数ある場合。

./pid.sh sshd
1475 /usr/sbin/sshd
1531 /usr/sbin/sshd
1601 /usr/sbin/sshd


フルパス指定することも出来ます。
同一プログラム名で異なるフォルダに配置されているものもたまにあるので、
それを区別したいときはパスを指定します。

./pid.sh /usr/bin/sshd
1475 /usr/sbin/sshd
1531 /usr/sbin/sshd
1601 /usr/sbin/sshd

(結果はイメージです)

欠点

動作がめちゃんこ遅い。リダイレクトって重いのかなー。それともforあたりかな。
また、プログラム名の探索はgrepを使ってやっているので、
"*"とか入っちゃうと任意長マッチになってしまう。
"mysql*"とすれば、mysqlとmysqldが取得できてしまう。

おまけ(Perl)

プロトタイプでちゃっちゃか書いたもの。
無駄が多いけどシェルスクリプトと比べて速く結果が出る。

#!/usr/bin/perl

use strict;
use warnings;

my $program = $ARGV[0] || die 'usage $0 [PROGRAM_NAME]';

my @line;
for my $target ('fd','exe'){
        my $ret = `ls -l /proc/*/$target 2>/dev/null | grep -e '$program' -e '^/proc'`;
        push @line , split(/\r?\n/, $ret);
}

my $pid;
$program = "/$program" if $program !~ /\//;

foreach my $line (@line){
        my $fullpath = `echo "$line" | awk {'printf \$11'}`;

        # PID
        if($line =~ /\/proc\/(\d+)\/(?:fd|exe)/){
                $pid = $1;
        }
        # program name matching
        if($fullpath && $fullpath =~ /$program$/){
                print "$pid $fullpath\n";
        }
}