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
スクリプトファイルは以上のようになる。