05. 環境変数とコマンド実行(工事中)

他のshellスクリプトと連動させて動かす場合などに、環境変数へのアクセス方法を知っておくことは必要です。また、shellコマンドの実行を含めて、例えばRuby記述で統一して処理を書きたいときなどには、shellコマンド実行方法を知っておくことは必要です。

環境変数関係については、02. 制御構文の中にも記述しています。

--- tcsh

このスクリプトでは特に気に留めておくことはないかもしれませんが、1つだけ書いておきたいと思います。

特定の変数、環境変数が「定義されているか否か」を把握する書き方です。

if ( $?ENV ) then

この例では、変数ENVが「定義されている場合」という意味になります。

--- Perl

環境変数へのアクセスは

$ENV{'ENV'} #ENVは環境変数名を指定

で行います。

コマンドを実行し、実行後の標準出力を受け取る書き方と、実行後の返り値を受け取る書き方があります。

以下の例では、env.txt に対して grep がマッチするケースとマッチしないケースを示しています。返り値は $? で受け取りますが、コマンド実行後の返り値のみ確認できればいいときは、

$result = system("shell command");

形式で記述します。

----- env.txt

abcdefg

-----

#!/usr/bin/perl
use warnings;
$a = `grep abc env.txt`;
print "---\n";
print "exec result is $a\n";
print "---\n";
print "return value is $?\n";
$a = `grep hoge env.txt`;
print "---\n";
print "exec result is $a\n";
print "---\n";
print "return value is $?\n";

実行結果:

---
exec result is abcdefg
---
return value is 0
---
exec result is
---
return value is 256

--- Ruby

環境変数へのアクセスは

ENV.fetch("ENV") #ENVは環境変数名を指定

で行います。

以下の例では、env.txt に対して grep がマッチするケースとマッチしないケースを示しています。Rubyには多数のshellコマンド実行方法があるようですが、そのうち幾つかを例示します。コマンドの実行結果は $? で受け取ります。以下に示す、コマンドの実行結果を puts しているところでは、文字列で表示されておりますが、条件チェックを行う際は数値として扱われます。つまり、ふつうに if 文で処理することができます。

3つの実行方法を例示しています。

  • バッククォートでくくる:`grep abc env.txt`
  • %xでくくる:%x(grep abc env.txt)
  • systemでくくる:system("grep abc env.txt")

バッククォートでくくる記法と%xでくくる記法では、同様の振る舞いをするように見えます。実行結果を受け取る場合は、これらの記法がいいようです。

systemでくくる記法では、実行結果ではなく返り値を受け取るようなので、上記2記法と区別して使用してください。

なお、詳しく調べておりませんが、exec("grep abc env.txt")と書いて実行すると、後段が実行されませんでしたので、ここでは取り扱わないことにしました。

#!/usr/bin/ruby -w
# grepを実行してマッチするケース
puts "--- exec cmd"
result0 = `grep abc env.txt`
puts "- disp cmd result"
puts result0
puts "- disp return val"
puts $?
puts ""
puts "--- exec cmd"
result1 = %x(grep abc env.txt)
puts "- disp cmd result"
puts result1
puts "- disp return val"
puts $?
puts ""
puts "--- exec cmd"
result2 = system("grep abc env.txt")
puts "- disp cmd result"
puts result2
puts "- disp return val"
puts $?
puts ""
# grepを実行してマッチしないケース
puts "--- exec cmd"
result0 = `grep hoge env.txt`
puts "- disp cmd result"
puts result0
puts "- disp return val"
puts $?
puts ""
puts "--- exec cmd"
result1 = %x(grep hoge env.txt)
puts "- disp cmd result"
puts result1
puts "- disp return val"
puts $?
puts ""
puts "--- exec cmd"
result2 = system("grep hoge env.txt")
puts "- disp cmd result"
puts result2
puts "- disp return val"
puts $?
puts ""

実行結果:

--- exec cmd
- disp cmd result
abcdefg
- disp return val
pid 21412 exit 0
--- exec cmd
- disp cmd result
abcdefg
- disp return val
pid 20148 exit 0
--- exec cmd
abcdefg
- disp cmd result
true
- disp return val
pid 20072 exit 0
--- exec cmd
- disp cmd result
- disp return val
pid 21820 exit 1
--- exec cmd
- disp cmd result
- disp return val
pid 21072 exit 1
--- exec cmd
- disp cmd result
false
- disp return val
pid 22512 exit 1

--- Python

環境変数へのアクセスは

import os

os.environ.get('ENV',"hoge") #ENVは環境変数名を指定

で行います。第二引数は、定義されていない環境変数へアクセスした時に返る値です。

Pythonによるshellコマンド実行ですが、調べたところ subprocess を使うようにすることが推奨されているようです。ちょっと複雑ではありますが、subprocess を使った例を示します。

以下の例において、grepがマッチするケースとマッチしないケースを書いておりますが、いくつか補足しておこうと思います。

  • shlex
    • これは、コマンド文字列を「適切」に分割するために、使用することが推奨されているようです。subprocess.Popenの第一引数 args のところに、直接 "grep abc env.txt" と書くことはできません。
  • subprocess
    • shell=Trueにすると、以下の例は動きません。
    • stdout指定を省略すると、以下の例は動きません。
    • stderr指定は、以下の例では省略しても動作します。
#!/usr/bin/python
import shlex, subprocess
print "===== grep match case"
cmd_line = "grep abc env.txt"
args = shlex.split(cmd_line)
p = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
dStdout, dStderr = p.communicate()
print "--- stdout"
print dStdout
print "--- return val"
print p.returncode
print "===== grep unmatch case"
cmd_line = "grep hoge env.txt"
args = shlex.split(cmd_line)
p = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
dStdout, dStderr = p.communicate()
print "--- stdout"
print dStdout
print "--- return val"
print p.returncode

実行結果:

===== grep match case
--- stdout
abcdefg
--- return val
0
===== grep unmatch case
--- stdout
--- return val
1