プロセスIDから実行パス・環境変数を取得する

こんにちわ
[グローバルセンス株式会社](https://gb-sense.com)のskanehiraです。

今回はタイトル通り、プロセスIDからプログラムの実行パス・環境変数を取得する方法を書いていきます。

以前、アプリのバグ分析でプロセスが実際読み込んだ環境変数を知る必要があって、その時に用いたやり方です。
情報が無い上、このプロセスを止めたいけど実行パスが分からない…っていう場合に使えるTipsかと思います。

今回はtomcatをたとえに説明していきます。

# **プロセスIDを確認**
まずはプロセスIDを知るところからです。

```shell-session
[skanehira@localhost ~]$ ps aux | grep tomcat
tomcat    1347  0.4  5.7 2311708 58548 ?       Ssl  19:25   0:01 /usr/lib/jvm/jre/bin/java -classpath /usr/share/tomcat/bin/bootstrap.jar:/usr/share/tomcat/bin/tomcat-juli.jar:/usr/share/java/commons-daemon.jar -Dcatalina.base=/usr/share/tomcat -Dcatalina.home=/usr/share/tomcat -Djava.endorsed.dirs= -Djava.io.tmpdir=/var/cache/tomcat/temp -Djava.util.logging.config.file=/usr/share/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager org.apache.catalina.startup.Bootstrap start
skanehi+  1437  0.0  0.0 112676   980 pts/0    R+   19:31   0:00 grep --color=auto tomcat
[skanehira@localhost ~]$
```

現在起動しているプロセスIDが**1347**ですね。

# **プロセス起動時の環境変数を確認**
Linuxではプロセスが立ち上がると[/proc]にプロセスID名のディレクトリが作られます。

各プロセスディレクトリにはプロセス関連の情報を入っています。
環境変数、実行ディレクトリなどなど…

実際tomcat起動時にどんな環境変数を読み込んでいるのかを見てみましょう。

```shell-session
[skanehira@localhost ~]$ sudo cat /proc/1347/environ
TOMCATS_BASE=/var/lib/tomcats/SHELL=/sbin/nologinCATALINA_HOME=/usr/share/tomcatOLDPWD=/NAME=USER=tomcatTOMCAT_CFG_LOADED=1PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/binPWD=/usr/share/tomcatJAVA_HOME=/usr/lib/jvm/jreLANG=ja_JP.UTF-8SHLVL=0HOME=/usr/share/tomcatSECURITY_MANAGER=falseLOGNAME=tomcatCATALINA_TMPDIR=/var/cache/tomcat/temp[skanehira@localhost ~]$
[skanehira@localhost ~]$
```

見づらいので、改行するとこんな感じになります。

```shell-session
TOMCATS_BASE=/var/lib/tomcats/
SHELL=/sbin/nologin
CATALINA_HOME=/usr/share/tomcat
OLDPWD=/
NAME=
USER=tomcat
TOMCAT_CFG_LOADED=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
PWD=/usr/share/tomcat
JAVA_HOME=/usr/lib/jvm/jre
LANG=ja_JP.UTF-8
SHLVL=0
HOME=/usr/share/tomcat
SECURITY_MANAGER=false
LOGNAME=tomcat
CATALINA_TMPDIR=/var/cache/tomcat/temp
```

# **プロセス起動時の実行パスを確認**

プロセスディレクトリ下には、exeというファイルがあります。
このファイルはプロセスの本体へのシンボリックリンクになっています。
ので、lsコマンドで実際の実行パスを確認することが出来ます。

```shell-session
[skanehira@localhost ~]$ sudo ls -l /proc/1347/exe
lrwxrwxrwx. 1 tomcat tomcat 0  2月 22 19:25 /proc/1347/exe -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/bin/java
[skanehira@localhost ~]$
```

実際psコマンドで表示されたコマンドのパスと同じですね。

# **おまけ**
grepとawkを用いるとワンライナーでパスとれます。

```shell-session
[skanehira@localhost ~]$ sudo ls -l /proc/`ps -aux | grep tomcat | grep -v grep | awk {'print $2'}`/exe | awk {'print $11'}
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/bin/java
[skanehira@localhost ~]$
```

順番を追って説明しますとgrepの-vでtomcatのプロセスだけを抽出します。

```shell-session
[skanehira@localhost ~]$ ps -aux | grep tomcat | grep -v grep
tomcat    1347  0.1  5.7 2311708 58748 ?       Ssl  19:25   0:04 /usr/lib/jvm/jre/bin/java -classpath /usr/share/tomcat/bin/bootstrap.jar:/usr/share/tomcat/bin/tomcat-juli.jar:/usr/share/java/commons-daemon.jar -Dcatalina.base=/usr/share/tomcat -Dcatalina.home=/usr/share/tomcat -Djava.endorsed.dirs= -Djava.io.tmpdir=/var/cache/tomcat/temp -Djava.util.logging.config.file=/usr/share/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager org.apache.catalina.startup.Bootstrap start
[skanehira@localhost ~]$
```

これだとプロセスID以外の不要な情報がありますので、
awkを用いて２列目のプロセスIDを抽出します。

```shell-session
[skanehira@localhost ~]$ ps -aux | grep tomcat | grep -v grep | awk {'print $2'}
1347
[skanehira@localhost ~]$
```

コマンドを``で囲うと実行結果が返却されます。

```shell-session
[skanehira@localhost ~]$ echo `ps -aux | grep tomcat | grep -v grep | awk {'print $2'}`
1347
[skanehira@localhost ~]$
```

その仕組を利用すると

```
/proc/`ps -aux | grep tomcat | grep -v grep | awk {'print $2'}`/exe
```
は

```
/proc/1347/exe
```

になります。

あとはexeのシンボリックリンクは11列目に表示されます。

```shell-session
[skanehira@localhost ~]$ sudo ls -l /proc/`ps -aux | grep tomcat | grep -v grep | awk {'print $2'}`/exe
lrwxrwxrwx. 1 tomcat tomcat 0  2月 22 19:25 /proc/1347/exe -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/bin/java
```

ので、awkで11列目だけ抽出すると

```shell-session
[skanehira@localhost ~]$ sudo ls -l /proc/`ps -aux | grep tomcat | grep -v grep | awk {'print $2'}`/exe | awk {'print $11'}
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/bin/java
[skanehira@localhost ~]$
```

になるというわけです。　

# 最後に
今回はTipsになりましたが、何か困った時このやり方が役に立てればと思います。
awkも結構色々と面白いし奥深いのですが、機会があれば勉強がてらに記事を書こうと思います。