python3
argparse
fileinput

Python fileinput と argparse の両立

たとえば、Perl で以下のように書くととても便利です。

while(<>){
    print $_;
}

何が便利かというと、以下2種類からの入力を受け付けられます。

  • 標準入力からの読み込み
  • 引数に指定したファイルの読み込み

Python で同じことは fileinput を使うとできるようです。

#!/usr/bin/env python
import fileinput

for line in fileinput.input():
    print(line, end="")

ここで、fileinputargparse と単純に組み合わせてみます。

#!/usr/bin/env python

import argparse
import fileinput

parser = argparse.ArgumentParser(prog="cata.py", description="fileinput & argparse")
parser.add_argument('-i', '--info', action='store_true', help='Print information')
args = parser.parse_args()

for line in fileinput.input():
    print(line, end="")

するとこんなエラーが(泣)

$ ./catf_ng.py  file?.txt
usage: cata.py [-h] [-i]
cata.py: error: unrecognized arguments: file0.txt file1.txt file2.txt

解決方法が下記のサイトにありました:grinning:
https://gist.github.com/martinth/ed991fb8cdcac3dfadf7

上記サイトには最終的な記述例が無かったのと、同様の内容が日本語サイトでヒットしなかったで、この記事にてメモを残したいと思います。

#!/usr/bin/env python

import argparse
import fileinput

parser = argparse.ArgumentParser(prog="cata.py", description="fileinput & argparse")
parser.add_argument('files', metavar='FILE', nargs='*', help='files to read, if empty, stdin is used')
parser.add_argument('-i', '--info', action='store_true', help='Print information')
args = parser.parse_args()

for line in fileinput.input(files=args.files):
    print(line, end="")

最後におまけで、上記add_argument()で追加したオプション('-i', '--info')で機能を追加してみました。

#!/usr/bin/env python

import argparse
import fileinput

parser = argparse.ArgumentParser(prog="cati.py", description="cat with file infomation")
parser.add_argument('files', metavar='FILE', nargs='*', help='files to read, if empty, stdin is used')
parser.add_argument('-i', '--info', action='store_true', help='Print filename and line no')
args = parser.parse_args()

for line in fileinput.input(files=args.files):
    if(args.info):
        if(fileinput.isfirstline()):
            print("*** {}".format(fileinput.filename()))
        print("{:6}\t".format(fileinput.filelineno()), end="")
    print(line, end="")

上記スクリプトはオプション無しだと cat だけします。
たとえば、以下3つのファイルを用意します。

file0.txt
I am Nozomi.
Are you Nozomi.
Yes, I am.

file1.txt
This is my bag.
That is your pen.
Is that a pen?
Yes, it is.
No, it is not.
It is a pencil.

file2.txt
He is my friend.
She is not from America.
Do you study English?
I like soccer.

"--info"または "-i" をつけて実行すると以下のように出力します。

$ ./cati.py --info file?.txt
*** file0.txt
     1  I am Nozomi.
     2  Are you Nozomi.
     3  Yes, I am.
     4  
*** file1.txt
     1  This is my bag.
     2  That is your pen.
     3  Is that a pen?
     4  Yes, it is.
     5  No, it is not.
     6  It is a pencil.
     7  
*** file2.txt
     1  He is my friend.
     2  She is not from America.
     3  Do you study English?
     4  I like soccer.
     5