👏

Pythonワンライナーで解く『シェル・ワンライナー160本ノック』第1章(問題1から問題11まで)

2023/01/15に公開

はじめに

この記事では、書籍『シェル・ワンライナー160本ノック』の問題をPythonワンライナーで解いてみます。シェル芸もPythonも素人ではありますが、精一杯取り組んでいきますので、何卒よろしくお願いいたします。今回は第1章の問題を解きます。

対象読者

シェル芸とPythonを愛する人々に読んでいただけますと幸いです。

注意

私のPythonワンライナーが正しい保証はありませんので、ご注意くださいませ。

書籍情報

書籍『シェル・ワンライナー160本ノック』のページです。
https://gihyo.jp/book/2021/978-4-297-12267-6
書籍『シェル・ワンライナー160本ノック』のGitHubのページです。
https://github.com/shellgei/shellgei160

参考記事

Pythonワンライナーの記事です。参考にさせていただきました。ありがとうございます。
https://b.ueda.tech/?page=python_shellgei

問題1

それでは、さっそくPythonワンライナーで問題を解いていきます。まず、a=open("files.txt","r");b=a.readlines();a.close();でファイルの内容を読み込みます。次に、b=[re.findall(".*\.exe$",c) for c in b];でexeファイルだけを抜き出します。そして、最後に、[print(c[0]) for c in b if c]で出力します。

 python3 -c 'import re;a=open("files.txt","r");b=a.readlines();a.close();b=[re.findall(".*\.exe$",c) for c in b];[print(c[0]) for c in b if c]'

ファイルの読み込みについて、こちらの記事を参考にさせていただきました。ありがとうございます。
https://www.javadrive.jp/python/file/index2.html
文字列の検索方法について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://hibiki-press.tech/python/find_and_in/439
Pythonの正規表現について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3
リストの内包表記でif文を使う方法について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://atmarkit.itmedia.co.jp/ait/articles/2107/06/news020.html

問題2

次は画像変換の問題です。まずa=glob.glob("*.png")で画像のファイルパスを取得します。次にb=[b[:-3]+"jpg" for b in a]で変換後のファイルパスを生成します。そして、c=[Image.open(c) for c in a]で画像を開き、c=[d.convert("RGB") for d in c]で変換して、[c[d].save(b[d],"JPEG") for d in range(len(c))]で保存します。

python3 -c 'import glob;from PIL import Image;a=glob.glob("*.png");b=[b[:-3]+"jpg" for b in a];c=[Image.open(c) for c in a];c=[d.convert("RGB") for d in c];[c[d].save(b[d],"JPEG") for d in range(len(c))]'

Pillowの使い方について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://hk29.hatenablog.jp/entry/2020/06/14/232653

問題3

次はファイル名の変更を行う問題です。まずa=glob.glob("*")でファイルパスを取得します。その後、a[b].zfill(7)でファイル名の0埋めをしつつ、os.rename(a[b],a[b].zfill(7))でファイル名を変更しています。

python3 -c 'import os,glob;a=glob.glob("*");[os.rename(a[b],a[b].zfill(7)) for b in range(len(a))]'

文字列の0埋めについて、こちらの記事を参考にさせていただきました。ありがとうございます。
https://note.nkmk.me/python-zero-padding/
ファイル名の変更について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://www.javadrive.jp/python/file/index16.html

問題4

次はファイル削除の問題です。execを使ったらもう普通のPythonですね。a=glob.glob("*")でファイルパスを取得し、c=open(a[b],r)でファイルを開き、if c.readline()==d:\n\t\tos.remove(a[b])10に一致したファイルを削除しています。一度に開くことができるファイル数には限りがあるので、必ずc.close()しましょう。

python3 -c 'import os,glob;a=glob.glob("*");r="r";d="10\n";exec("for b in range(len(a)):\n\tc=open(a[b],r)\n\tif c.readline()==d:\n\t\tos.remove(a[b])\n\tc.close()")'

ファイルの削除について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://note.nkmk.me/python-os-remove-rmdir-removedirs-shutil-rmtree/
execについて、こちらの記事を参考にさせていただきました。ありがとうございます。
https://qiita.com/KTakahiro1729/items/b2b1a9b82fc6e6d8c158

問題5

次はファイルから情報を抽出する問題です。a=open("ntp.conf","r");b=a.readlines();a.close()でファイルの内容を読み取ります。その後、c=[re.findall("^pool.*$",c) for c in b]poolの行を抜き出し、e=[[re.findall("\s.*",e) for e in d] for d in c if d];[print(f[0][0]) for f in e]'で出力します。

python3 -c 'import re;a=open("ntp.conf","r");b=a.readlines();a.close();c=[re.findall("^pool.*$",c) for c in b];e=[[re.findall("\s.*",e) for e in d] for d in c if d];[print(f[0][0]) for f in e]'

問題6

次は描画問題です。素直に解きます。

python3 -c 'print("     x\n    x\n   x\n  x\n x\n")'

問題7

次は表計算の問題です。まず、Pandasを使ってa=p.read_csv("kakeibo.txt",sep=" ",header=None)のようにスペース区切りのcsvファイルとしてデータを読み込みます。その後、b=a.values.tolist()でリストに変換します。最後にexecの中で消費税率が10%と8%のときの場合分けをして合計の計算をしています。

 python3 -c 'import pandas as p;a=p.read_csv("kakeibo.txt",sep=" ",header=None);b=a.values.tolist();c=0;e="20191001";f="*";exec("for d in b:\n\tif str(d[0])<e or d[1][0]==f:\n\t\tc+=int(d[2]*1.08)\n\telse:\n\t\tc+=int(d[2]*1.1)");print(c)'

Pandasの使い方について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://sunafukin.jp/?p=1297
リストへの変換について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://note.nkmk.me/python-pandas-list/

問題8

次はログファイルの集計問題です。まず、a=p.read_csv("access.log",sep=" ",header=None)でファイルを読み込み、b=a.values.tolist()でリストに変換します。その後、c=[c[3] for c in b];e=[re.findall(":[0-9][0-9]:",d) for d in c];f=[re.findall("[0-9][0-9]",f[0]) for f in e];で時刻情報を抜き出します。最後にexec("for g in f:\n\tif int(g[0])<12:\n\t\th+=1\n\telse:\n\t\ti+=1");print("午前:"+str(h));print("午後:"+str(i))で午前と午後をカウントしています。

python3 -c 'import pandas as p;import re;a=p.read_csv("access.log",sep=" ",header=None);b=a.values.tolist();c=[c[3] for c in b];e=[re.findall(":[0-9][0-9]:",d) for d in c];f=[re.findall("[0-9][0-9]",f[0]) for f in e];h=0;i=0;exec("for g in f:\n\tif int(g[0])<12:\n\t\th+=1\n\telse:\n\t\ti+=1");print("午前:"+str(h));print("午後:"+str(i))'

問題9

次もログの問題です。a=open("log_range.log","r");b=a.readlines();a.close();でファイルの内容を読み取ります。その後、年月日+時刻情報の文字列を比較して、2016年12月24日21時台~2016年12月25日3時台までのデータだけ抜き出します。

python3 -c 'import re;a=open("log_range.log","r");b=a.readlines();a.close();d=[re.findall("""[0-9][0-9]/Dec/2016 [0-9][0-9]:[0-9][0-9]:[0-9][0-9]""",d) for d in b];[print(b[e]) for e in range(len(b)) if d[e][0]>"""24/Dec/2016 20:59:59""" and d[e][0]<"""25/Dec/2016 04:00:00"""]'

問題10

次は置換の問題です。まずa=open("headings.md","r");b=a.readlines();a.close();でファイルの内容を読み取ります。次にc="## ";d="# ";e="";h="---";i="===";で置換の材料を用意します。その後、execにおいて置換を行います。最後にa=open("headings.md","w");[a.write(j) for j in b];a.close()で置換後のデータをファイルに書き込みます。

python3 -c 'import re;a=open("headings.md","r");b=a.readlines();a.close();c="## ";d="# ";e="";h="---";i="===";f=len(b);g=0;exec("while g < f:\n\tif c in b[g]:\n\t\tb[g]=re.sub(c,e,b[g]);b.insert(g+1,h);f+=1\n\telif d in b[g]:\n\t\tb[g]=re.sub(d,e,b[g]);b.insert(g+1,i);f+=1\n\tg+=1");a=open("headings.md","w");[a.write(j) for j in b];a.close()'

文字列の置換について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://note.nkmk.me/python-str-remove-strip/
リストの挿入について、こちらの記事を参考にさせていただきました。ありがとうございます。
https://www.javadrive.jp/python/list/index7.html
ファイルへの書き込みについて、こちらの記事を参考にさせていただきました。ありがとうございます。
https://www.javadrive.jp/python/file/index3.html

問題11

第1章の最後の問題です。まずa=open("gijiroku.txt","r");b=a.readlines();a.close();でファイルの内容を読み込みます。次にd1="すず";d2="鈴木";e1="さと";e2="佐藤";f1="やま";f2="山田";g1="\n";g2=":";で置換の材料を用意します。その後、execにおいて置換を行います。最後に、a=open("gijiroku.txt","w");[a.write(h) for h in b];a.close()でファイルに置換後のデータを書き込んでいます。

python3 -c 'a=open("gijiroku.txt","r");b=a.readlines();a.close();b.append("\n");d1="すず";d2="鈴木";e1="さと";e2="佐藤";f1="やま";f2="山田";g1="\n";g2=":";i=0;exec("while i < len(b):\n\tif d1 in b[i]:\n\t\tb[i]=b[i].replace(d1,d2);b[i]=b[i].replace(g1,g2);i+=2\n\tif e1 in b[i]:\n\t\tb[i]=b[i].replace(e1,e2);b[i]=b[i].replace(g1,g2);i+=2\n\tif f1 in b[i]:\n\t\tb[i]=b[i].replace(f1,f2);b[i]=b[i].replace(g1,g2);i+=2\n\ti+=1");a=open("gijiroku.txt","w");[a.write(h) for h in b];a.close()'

おわりに

すべてのシェル芸とPythonと読者の方々に感謝します。ありがとうございました。楽しかったです。

スクラップ:シェル芸とPythonワンライナー

スクラップでシェル芸とPythonワンライナーの情報をまとめています。
https://zenn.dev/yusukekato/scraps/9db826dd932f1b

ブログを移行しました

続きはこちらから
https://yusukekato.jp/20230418.html

Discussion