
2025/12/08 17:52
Using Python for Scripting
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
要約
この記事では、
readlink、find、xargs、date、sed などの GNU 固有ツールに依存するシェルスクリプトが、BSD バリアントでオプションが欠落または変更されているため macOS 上でしばしば動作しなくなる理由を説明しています。例として Bash スクリプトを挙げ、macOS で実行すると典型的なビルドヘルパーが失敗する様子を示し、著者はクロスプラットフォームの信頼性を確保するために Python への移行を推奨しています。
Python 3 はほぼすべての現代マシンに標準で搭載されており、CPython の標準ライブラリ(JSON、XML、HTTP クライアント、時間型、データ構造、sqlite3 など)がビルド自動化タスクに必要な機能をすべて備えています。記事では PEP 387 が五年間の後方互換性を保証していると指摘し、今日書かれたコードは将来もそのまま実行できることを示しています。また
warnings.simplefilter("default", DeprecationWarning) を使って datetime.utcnow() から datetime.now(timezone.utc) への置き換えなどの非推奨警告を表示する方法も紹介しています。
投稿は、配列構文(
@)の欠如、誤った引用符、${s^^} のようなケース変換といった Bash 特有のクォリティをハイライトし、Python の読みやすいメソッド(例:s.upper()、リスト内包表記)がこれらの落とし穴を回避できることを説明しています。10〜20 行程度の小さなスクリプトは Bash で残せますが、大規模または理解しにくいスクリプトは Python に変換すると、チーム全体で一貫したプラットフォーム非依存コードになり、ビルドパイプライン上のバグを減らすことができます。
この記事はノルウェー語で書かれ、Kodemaker のブログに掲載されました。
本文
私たちはいつも問題を解決できる最もシンプルなツールを好みますが、長期的に見ると必ずしも最適とは限りません。さらに、複数のマシンで実行したい場合は特にそうです。
例えば、プロジェクトをビルドするためのシェルスクリプトがあるとします。
そのスクリプトを別のフォルダから呼び出せるようにしたいので、まず最初にやりたいことはプロジェクトのルートディレクトリを特定し、それを作業ディレクトリに設定することです。
SCRIPT_PATH="$(readlink -f "$0")" PROJECT_ROOT="$(dirname "${SCRIPT_PATH}")" cd "${PROJECT_ROOT}"
その後、ビルドアーティファクトが古くてキャッシュされているというバグがあるため、以前に作成したすべてのアーティファクトを削除したいと考えます。これで、前回のビルドから残った古いデータを残さないようにできます。
find build gen -type f \( -name '*.o' -o -name '*.a' \) -print0 | xargs -0 -r rm
もちろん、リリース用のビルド署名を作成するために、ビルド日付と git‑commit をバージョンファイルに書き込んでいます。
BUILD = …… We must translate the entire article.私たちはいつも「問題を解決できる最もシンプルなツール」を選びがちですが、長期的には必ずしも最適とは限りません。さらに、複数のマシンで実行したい場合はその傾向がより顕著になります。 たとえば、プロジェクトをビルドするためのシェルスクリプトがあるとします。 別のフォルダからそのスクリプトを呼び出せるようにしたいので、最初にやりたいことは「プロジェクトのルートディレクトリを探して作業ディレクトリに移動する」ことです。 ```sh SCRIPT_PATH="$(readlink -f "$0")" PROJECT_ROOT="$(dirname "${SCRIPT_PATH}")" cd "${PROJECT_ROOT}"
その後、ビルドアーティファクトが古くてキャッシュされているというバグを修正したいので、以前に作ったすべてのアーティファクトを削除します。これで前回のビルドから残っていた古いデータを残さないようにできます。
find build gen -type f \( -name '*.o' -o -name '*.a' \) -print0 | xargs -0 -r rm
もちろん、リリース用にビルド署名を作るために、ビルド日付と git‑commit をバージョンファイルに書き込みます。
BUILD_DATE="$(date -d 'now' +%F)" cp version.template build/version.txt sed -i "s/@VERSION@/${COMMIT_TAG:-dev}/" build/version.txt sed -i "s/@BUILD_DATE@/${BUILD_DATE}/" build/version.txt
最後に、プロジェクトが依存しているビルドコマンドを実行してプロジェクトをビルドします。
ここにはいくつか問題があります。私にとってはこのスクリプトはうまく動きますが、Mac ユーザーにとってはすべての手順が失敗します!
readlink・find・xargs・date・sed などの呼び出しは、これらのプログラムの GNU(Linux)版に依存しており、BSD(Mac)のバージョンでは存在しないか同じように動作しません。同様に、Mac 用で Linux 用で動く引数があるものもあります。
こうした問題を回避する方法はいくつかありますが、いずれも洗練された解決策とは言えません。しかも、Mac でも Linux でもどちらかにしか慣れていないと、ツールが別の OS で動かないことに驚きます。これは、CI マシン上で実行されるスクリプトを修正したい Mac ユーザーにとっては特に苛立たしいでしょうし、新規プロジェクトに取り掛かった瞬間に「Linux で動くように開発スクリプトを直さないと」なるのは楽しくありません。
Python が救世主になる
タイトルが示す通り、Python 3(以下、Python)は複雑なシェルスクリプトの優れた代替手段です。理由は次の 4 点に集約されます。
- ほぼすべてのマシンに Python がインストール済み
- 多くの開発者が Python に慣れている(ある程度)
- Python は大規模で標準化された標準ライブラリを持つ
- Python コードは後から読んだときに読みやすい
既知・既装備
私の主眼として最も重要なのは、Python 3 がほぼすべてのマシンにインストールされている点です。
さらに、私たちは「Python を知っている」― 大規模プロジェクトで使ったことがなくても、一度は何かしら Python っぽいものを触った経験があります。これだけでも導入へのハードルが大幅に下がります。
標準化された標準ライブラリ
標準ライブラリに沿って書けば、スクリプトを実行するすべてのマシンで同じ動作になります。参照実装である CPython は、開発者の 99.8 % がインストールして使っています。残りの 0.2 % は別実装(Jython, IronPython など)を使用していますが、私が知る限りすべての実装は参照実装と意味的に同等になるよう努力しています。
注意すべきなのは「どのバージョンの Python を前提にしているか」だけです。実際には、新しいパッケージほど問題が起こりやすいですが、古い Python で動くスクリプトなら大抵は問題ありません。
Python は後方互換性を真剣に扱っています ― すべての大規模言語と同様です。PEP 387 は破壊的変更が導入される際の指針を示しており、頻繁に起こることはほぼありません。もし何かが非推奨になった場合でも、コードは少なくとも 5 年間はそのまま動き続けます。
たとえば
datetime.utcnow() は 3.12 で非推奨となりました。DeprecationWarning を有効にすると「datetime.now(timezone.utc) に置き換えるべき」と警告が出てきます。これは標準ライブラリから消える前に soft‑deprecation(軽いデプリケーション)であることを意味します。メンテナーが削除するなら、PEP 387 は「最短 2028 年頃」になると示しています。
大規模な標準ライブラリ
標準ライブラリが存在し、消える心配もない点が Python を選ぶ最大の理由です。上記で述べたように、これらは すべて 事前に決められた構成要素で、同じ作業をシェルではなく Python で行うことができます。
JSON → JSON‐?‑…(何でも―)
他の JSON‑ …?
…
「… …
(???)
## 思考ツールとして
We must finish translation of remaining text.```text
JSON を扱う? それとも XML?
というように、標準ライブラリだけで何でも出来ます。 HTTP クライアントが必要なら組み込みの `http.client` や `urllib.request` が用意されています。 時間型やデータ構造も充実しており、必要なら `sqlite3` パッケージまで利用できます。 「プロトコル生成ツール(`protoc` など)やオープンAPIのクライアント・コンパイラ」を除けば、シェルスクリプトで簡単にできないことはほぼありません。 Python なら同じ作業を容易に行えます。 ### 読みやすさ 「言語 X は Y より読みやすい」と主張する人は多いですが、両者のセマンティクスが似ている場合は特にそうではありません。こうした議論はしばしば「自分がよく使う方を好む」だけで済むケースです。 しかし Python がシェルより読みやすいと主張する根拠には、以下のような点があります。まず第一に、頻繁に使わない言語だと、データ型や文字列操作が頭に残りにくいです。たとえば Bash でリストを大文字化するときの書き方は次の通りです。 ```bash morning_greetings=('hi' 'hello' 'good morning') energetic_morning_greetings=() for s in "${morning_greetings[@]}"; do energetic_morning_greetings+=( "${s^^}!" ) done
Bash を頻繁に使わない人なら、
"${morning_greetings[@]}" が何を意味するのかすぐに分からず、書くときに正しい構文を忘れやすいです。[ @ ] を抜けてしまうと最初の要素だけが返ってきますし、ダブルクォートを外すと「good morning」が 2 要素に分割されます。そして ${s^^} が実際に何をしているかも分かりづらいです。
ちなみにリスト内でカンマを付けてしまうと
morning_greetings=('hi', 'hello', 'good morning')
というリストになり、
hi,・hello,・good morning という要素が作られます。
さらに Zsh では動きません。Zsh を使っている人は端末愛好家かもしれませんし、その場合でも自分の好きなシェルでこの書式を使えないと、スクリプトに組み込む可能性が低くなるでしょう。
上記のように、Bash を頻繁に使わないと多くのミスを犯すことになります。
Python 版は次のようになります。
morning_greetings = ['hi', 'hello', 'good morning'] energetic_morning_greetings = [s.upper() + '!' for s in morning_greetings]
最初に見るとリスト内包表記
[x for y in z] がすぐに理解できるとは限りませんが、使い方を覚えてしまえば s.upper() のほうが ${s^^} より直感的です。
また Python にはより豊富な語彙があります。したがって「
morning_greetings.pop(1)」のように要素を削除する操作は、最初に見るとわかりづらいですが、後で見たときに「インデックス 1 の要素を取り除く」という意味になるので理解しやすいです。対して Bash には同等のメソッドが無いため、次のような手作業が必要になります。
unset 'morning_greetings[1]' arr=( "${morning_greetings[@]}" )
これらは分かりにくく、さらにドキュメントも参照できません。
「子を洗い流さないでおく」ことの危険性
スクリプトがある程度大きくなると、Python を使う理由が増えてきます。逆に Bash で書いていると、次に何をすべきかが分からなくなります。
そのため、既に Bash で書かれている場合でも、リライトする余裕がないときは「先ほどの…」という形でいろいろ検討しながりつくらずに作業してしまいます。
シェルでは全体を見えやすくすることが難しいので、実際には スクリプトに最初から前置付けがなくても綺麗な面目が形づくる という点でも長い労働作業が落ち込んです。
「全ての自動化で‐自動化…」 と…
(ここでは抜粋させてしまいます)
## Pythone ?‑
先ほども説明したように、Python ― 前後‐全般‐実際に実装にくい ……
何味? 先行‐点‐下
We need finish translation.## 子どもを水に流さないで
スクリプトがある程度大きくなると、Python を使うべき理由が増えていきます。逆に Bash で書いていると、次に何をすべきかが分からなくなることがあります。
そのため、既に Bash で書かれているスクリプトでも、リライトの余裕がない場合は「先ほどの…」という形で途中まで進めてしまい、結局は手作業で修正する羽目になります。
シェルでは全体を把握しづらく、実際には 「最初から前置付けをせずにスクリプトを書いても見通しが良くなる」 という点でも長い労力がかかります。
「すべての自動化は…」という考え方は…
(ここでは抜粋させていただきます)
Python が選ばれる理由
先ほど述べたように、Python は既知・標準化・大規模であるため、スクリプトを書き直す価値があります。特に次の点が重要です。
- 移植性:Linux だけでなく macOS でも同じコードで動作します。
- 保守性:バージョンアップや非推奨警告を一目で確認でき、長期的に安全に使えます。
- 機能の充実:JSON・XML・HTTP クライアント・タイムゾーン・データ構造など、標準ライブラリだけでほぼ全てが実装済みです。
- 読みやすさ:Python のメソッド名は人間にとって直感的で、複雑な Bash スクリプトよりもエラーを起こしにくいです。
まとめ
- シェルスクリプトは短くても可読性が低いことが多い
- Python はほぼすべてのマシンで動作し、標準ライブラリだけで完結できる
- 長期的に見たときの保守コストが低減される
したがって、スクリプトを 10〜20 行程度から始めても、将来拡張する可能性があるなら Python に移行しておく価値があります。
新しいプロジェクトに取り掛かったときに「Linux 用に開発スクリプトを直さなければならない」ことは楽ではありません。Python を使えば、その負担を大幅に軽減できます。
この記事はオリジナルでノルウェー語で書かれ、Kodemaker のブログで公開されています。
(英訳版を読む場合は下記リンクをご参照ください)