python script_file [file...]
Python はテキストフィルタとしての利用だけでなく、汎用なシステム操作記述言語としての利用に十分な組み込み関数や拡張モジュールが充実しており、シェル環境で足りない機能を外部コマンドとして拡充するだけの能力が備わっている。
Python スクリプトを外部コマンドとして利用する為には、Unix 環境では以下のような行頭から始めればよい。
#!/usr/bin/python :
また、コマンドラインオプションを指定するには、Perl, Ruby のように '-s' オプションでコマンドラインオプションによる大域変数の設定などはないので、自前でコマンドラインオプション解析を行うか、'getopt', 'argparse' モジュールを利用するか検討すべきだ。
Python には多様な拡張パッケージが備わり、その上、Ruby 以上に数多のサードパーティ製拡張パッケージが用意されている。インストール済みの拡張パッケージを利用するには、以下のようにする。
#!/usr/bin/python import stat :
代表的な Unix コマンドに相当する Python スクリプトを以下にあげる。
Python では '-l' オプションで print メソッドで自動的に改行がなされ、$, = で配列やリストのフィールドセパレータがスペースになる。
' '
#!/usr/bin/python import sys print " ".join(sys.argv[1:])
Ruby と比べるとかなり違和感がある。それは、'sys.argv[1:].join(" ")' のようなメソッドが用意されていないからであるが、'import string' した上で 'string.join(sys.argv[1:], " ")' とすれば多少違和感が無いが、これは廃止されるクラスメソッドだ。
このように、echo と同じ python スクリプトファイルは以上のようになる。
Python における終了コードは特に明示しない限り、正常終了である。
#!/usr/bin/python
このように、true と同じ python スクリプトファイルは以上のようになる。
Python における終了コードは 'sys' モジュールの 'sys.exit' 関数で指定できる。ちなみに、GNU Awk では可能だが、Awk では終了コードを制御できない。
#!/usr/bin/python import sys sys.exit(1)
実は、自動的に読み込まれる 'site' モジュールにより、以下のようにほぼ同等なことが出来てしまう。設計思想からして、理解不能な名前空間の扱いである。
#!/usr/bin/python exit(1)
このように、false と同じ python スクリプトファイルは以上のようになる。
#!/usr/bin/python
from datetime import datetime
print datetime.today().strftime("%c")
このように、date と同じ python スクリプトファイルは以上のようになる。
#!/usr/bin/python
import sys
import os
def dirname(p):
if not isinstance(p, str): return "."
if not len(p): return "."
if p == os.sep: return os.sep
if p == "." or p == "./": return "."
if p == ".." or p == "../": return "."
b = p.rstrip(os.sep)
i = b.rfind(os.sep)
if i < 0:
return "."
else:
b = b[0:i]
return b
argv = sys.argv[1:]
argv or sys.exit("usage: dirname path")
print dirname(argv[0]) # Do not use os.path.dirname().
Python 標準の 'os.path.dirname' は、残念ながら POSIX 規格に沿った仕様を有しない。よって、以上のように代替品を自作する必要がある。Python は各所 DOS の匂いがする。
このように、dirname と同じ python スクリプトファイルは以上のようになる。
#!/usr/bin/python
import sys
import os
def basename(p, x = ""):
if not isinstance(p, str): return "."
if not len(p): return ""
if p == os.sep: return os.sep
b = p.rstrip(os.sep)
i = b.rfind(os.sep)
if not i < 0:
b = b[i+1:]
if x and b[-len(x):] == x:
b = b[0:-len(x)]
return b
argv = sys.argv[1:]
argv or sys.exit("usage: basename string [suffix]\n basename [-a] [-s suffix] string [...]")
if len(argv) > 1:
print basename(argv[0], argv[1]) # Do not use os.path.basename().
else:
print basename(argv[0]) # Do not use os.path.basename().
Python 標準の 'os.path.basename' は、残念ながら POSIX 規格に沿った仕様を有しない。よって、以上のように代替品を自作する必要がある。Python は各所 DOS の匂いがする。
このように、basename と同じ python スクリプトファイルは以上のようになる。
#!/usr/bin/python import os import pwd name = pwd.getpwuid(os.getuid()).pw_name #name = os.getlogin() print name
このように、logname と同じ python スクリプトファイルは以上のようになる。
#!/usr/bin/python
import sys, getopt
import os
import pwd, grp
import re
opts, argv = getopt.getopt(sys.argv[1:], "hGgunr", [ "help", ])
g = { 'G': False, 'g': False, 'u': False, 'n': False, 'r': False,
'name': None, 'id': None, 'gname': None, 'gid': None, }
for o, a in opts:
if o in ('-h', '--help'):
sys.exit(0)
elif o == '-G': g['G'] = True
elif o == '-g': g['g'] = True
elif o == '-u': g['u'] = True
elif o == '-n': g['n'] = True
elif o == '-r': g['r'] = True
gids, gnames = [], {}
if not argv:
g['id'] = os.geteuid()
gids.append(os.getegid())
for group in os.getgroups():
gids.append(group)
if g['G']: gids.pop(0)
else:
if not re.match(r"^\d+$", argv[0]):
g['name'], g['id'] = pwd.getpwnam(argv[0]).pw_name, pwd.getpwnam(argv[0]).pw_uid
if not g['name']: sys.exit(1)
else:
g['id'] = int(argv[0])
g['name'], g['gid'] = pwd.getpwuid(g['id']).pw_name, pwd.getpwuid(g['id']).pw_gid
if not g['name']: sys.exit(1)
gids.append(g['gid'])
for grent in grp.getgrall():
gname, gid, members = grent.gr_name, grent.gr_gid, grent.gr_mem
members = filter(lambda id: id == g['id'], map(lambda member: pwd.getpwnam(member).pw_uid, members))
if members: gids.append(gid)
if g['G']:
if not g['n']:
if gids: sys.stdout.write(' '.join(map(lambda gid: str(gid), gids)))
else:
if gids: sys.stdout.write(' '.join(map(lambda gid: grp.getgrgid(gid).gr_name, gids)))
elif g['g']:
if not g['n']:
sys.stdout.write(str(gids[0]))
else:
g['gname'] = grp.getgrgid(gids[0]).gr_name
if not g['gname']: sys.exit(1)
sys.stdout.write(g['gname'])
elif g['u']:
if not g['n']:
sys.stdout.write(str(g['id']))
else:
g['name'] = pwd.getpwuid(g['id']).pw_name
if not g['name']: sys.exit(1)
sys.stdout.write(g['name'])
else:
g['name'], g['gid'] = pwd.getpwuid(g['id']).pw_name, pwd.getpwuid(g['id']).pw_gid
if not g['name']: sys.exit(1)
g['gname'] = grp.getgrgid(g['gid']).gr_name
if not g['gname']: sys.exit(1)
sys.stdout.write("uid=%u(%s) gid=%u(%s) " % (g['id'], g['name'], g['gid'], g['gname']))
sys.stdout.write("groups=")
for i in range(len(gids)):
if not gids[i] in gnames:
gname = grp.getgrgid(gids[i]).gr_name
if i != 0: sys.stdout.write(",")
sys.stdout.write("%u(%s)" % (gids[i], gname))
gnames[gids[i]] = gname
sys.stdout.write("\n")
このように、id と同じ python スクリプトファイルは以上のようになる。
#!/usr/bin/python
import sys, getopt
import stat
import time
import os, os.path
import re
opts, argv = getopt.getopt(sys.argv[1:], "hamcr:t:", [ "help", ])
g = { 'a': False, 'm': False, 'c': False, 'r': None, 't': None, }
for o, a in opts:
if o in ('-h', '--help'):
sys.exit(0)
elif o == '-a': g['a'] = True
elif o == '-m': g['m'] = True
elif o == '-c': g['c'] = True
elif o == '-r': g['r'] = a
elif o == '-t': g['t'] = a
ntime = time.time()
atime, mtime = None, None
if g['r']:
status = os.stat(g['r'])
else:
if g['t']:
m = re.match(r"(?:((?:\d{2})?\d{2}))?(\d{2})(\d{2})(\d{2})(\d{2})(?:\.(\d{2}))?$", g['t'])
if g['t']:
CCYY, MM, DD, hh, mm, SS = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)), int(m.group(5)), int(m.group(6))
if CCYY:
if CCYY <= 99:
CCYY += 1900 if (69 <= CCYY) else 2000
else:
CCYY = time.localtime(ntime).tm_sec + 1900
if not SS: SS = 0
ntime = time.mktime((CCYY, MM, DD, hh, mm, SS, 0, 0, -1))
if g['a'] and g['m'] or not g['a'] and not g['m']:
atime = status.st_atime if g['r'] else ntime
mtime = status.st_mtime if g['r'] else ntime
elif g['a']:
atime = status.st_atime if g['r'] else ntime
elif g['m']:
mtime = status.st_mtime if g['r'] else ntime
for a in argv:
if not g['c'] and not os.path.exists(a):
f = open(a, 'w')
f.close()
if not atime: atime = mtime
if not mtime: mtime = atime
if not atime: atime = ntime
if not mtime: mtime = ntime
os.utime(a, (atime, mtime))
このように、touch と同じ python スクリプトファイルは以上のようになる。
`du` コマンドを実現するには 'opendir', 'readdir', 'closedir' 及び 'stat', 'lstat' を使えれば十分だ。Python にはそれに対応する 'os.listdir', 'os.stat', 'os.lstat' がある。
#!/usr/bin/python
import sys
import stat
import os, os.path
import math
units = {
'K': 1024, # KibiBytes
'M': 1024*1024, # MebiBytes
'G': 1024*1024*1024, # GibiBytes
}
g = { 'H': False, 'L': False, 'a': False, 's': False, 'd': 0, 'h': False, 'S': 1, }
argv = sys.argv[1:]
while len(argv):
if argv[0] == '--': argv.pop(0); break
elif argv[0] == '-H': g['H'] = True
elif argv[0] == '-L': g['L'] = True
elif argv[0] == '-a': g['a'] = True
elif argv[0] == '-s': g['s'] = True
elif argv[0] == '-d' and 1 < len(argv): argv.pop(0); g['d'] = int(argv[0])
elif argv[0] == '-k': g['S'] = 2
elif argv[0] == '-m': g['S'] = 2*1024
elif argv[0] == '-g': g['S'] = 2*1024*1024
elif argv[0] == '-h': g['h'] = True
else: break
argv.pop(0)
def resize(size):
if not g['h']:
return str(long(math.ceil(size/g['S'])))
else:
if not size < units['G']/512:
p = 'G'
elif not size < units['M']/512:
p = 'M'
else:
p = 'K'
s = size/(units[p]/512)
if s < 1: p = 'B'
f = "%3.0f"
if not s < 1 and s < 10: f = "%3.1f"
return f % (s) + p
total_sizes = [ 0.0 ]
def do_one(one):
global total_sizes
size = 0
if os.path.isdir(one) and (g['L'] or (not g['L'] and not os.path.islink(one))):
if not (os.stat(one).st_mode & stat.S_IRUSR and os.stat(one).st_mode & stat.S_IXUSR): return
total_sizes.append(0.0)
for entry in os.listdir(one):
do_one("%s/%s" % (one, entry))
size = total_sizes.pop()
if (not g['s'] or (g['s'] and not len(total_sizes)-1)) and (not g['d'] or not g['d'] < len(total_sizes)-1):
print resize(size) + "\t" + one
else:
status = os.stat(one) if g['L'] and os.path.exists(one) else os.lstat(one)
if not status: return
size = status.st_blocks
if g['a']: print resize(size) + "\t" + one
total_sizes[len(total_sizes)-1] += size
if not argv:
do_one('.')
sys.exit(0)
while len(argv):
do_one(argv[0])
argv.pop(0)
このように、du と同じ python スクリプトファイルは以上のようになる。