プログラミング
コンピュータに指示を出す方法
Telling a Computer to Do Things (will-keleher.com)
要約
この記事は、開発者がコンピュータに指示を出すための基本的なスキルであるシェルスクリプティングの重要性について論じています。著者は、GUIに頼るだけでは限界があり、コマンドラインツールやスクリプトを使いこなすことで、より複雑なタスクを自動化し、生産性を向上させられると主張しています。シェルスクリプトの習得は、単なる構文だけでなく、利用可能なツール(fzf, xargs, sedなど)の知識が鍵となると述べています。
全文翻訳
コンピュータに指示を出す方法
キャリアの最初の数年間、私はコンピュータに指示を出す方法を知りませんでした。ターミナルからいくつかのコマンドを実行することはできましたが、一度に一つの単純なコマンドを実行することに限定されていました。私のターミナルは世界で最も悪いGUIであり、シェルはアプリケーションラッパーを持たないプログラムを開始する方法だと思っていました。根本的に、私はコンピュータに論理を伴うものや、複数のプログラムを組み合わせるようなことを達成させる方法を知りませんでした。
1つことを行い、次に別のことを行う
コマンドが失敗した場合、エラーメッセージをログに出力する
コンピュータが起動したときにプログラムを開始する
2つのコマンドを同時に実行する
ディレクトリ内のすべてのファイルに対してループ処理を行い、それぞれにアクションを実行する
あるコマンドの出力を別のコマンドの入力として使用する
理論的には、これらの種類のプログラムを書くためにNodeJSを使用できたかもしれません。実際には、私は決してそうしませんでした。これは部分的に考え方によるものでした。コマンドラインで使用するプログラムを、自分が制御できるものとして考えることに慣れていませんでした。残りはスキルの不足でした。私が使用しているプログラムを、私が書いたスクリプトに統合するほど十分に理解していませんでした。
それでも、私はシェルを学び続けました。そして、基本的なロジックを持つこのようなスクリプトをなんとかこなせるレベルにゆっくりと到達しました。
set +e
npm install
status_code=$?
if [[ "$status_code" != "0" ]]; then
echo "npm install で何かがうまくいきませんでした。authed されていることを確認するために ~/.npmrc を確認してください。"
exit 1
fi
set -e
シェルのスクリプティングにどれだけ慣れているかによりますが、あなたは今、早口でまくしたてているかもしれません。すみません。
(もし、まだ目が血走っていないなら、なぜそうなるべきかの理由を説明します:1)
私が書いたコマンドやスクリプトには問題がありましたが、それは私にとって変革的でした。既存のプログラムを組み合わせて目標を達成するようにコンピュータに指示する能力を突然得たのです。それは、プログラミングを学ぶこと自体から来る変化に少し似ていました。
何年にもわたって、私はゆっくりとより多くのシェルツールを学び、シェルの構文を理解するようになりました。新しいツールやパターンを学ぶと、ハンマーで解決すべき問題をドリルが必要な問題に使ってしまったことに気づき、苦痛を感じることがよくありました。
その間、私はたくさんの(信じられないほど優秀な!)エンジニアと仕事をしてきましたが、彼らはシェルを学ぶのにそれほど時間をかけず、代わりにGUIを使用してテストの実行、Gitの管理、データベースとの対話、日常的なタスクなどを行っていました。GUIに頼ることは、GUIが処理できるように設定されていないことを達成したいと思ったときまではうまく機能しますが、GUIの能力に限定される考え方に陥りやすいと思います。私は、whileを使ってコマンドを繰り返し実行する方法や、ディレクトリ内のすべてのファイルに同じ操作を行うためにforループを書く方法を知らないために、多大な労力を費やしている熟練したエンジニアを見てきました。
私は、GUI中心の考え方がシェルスクリプトの編集と保守に関しても問題になりうると考えています。ほとんどの企業には、BashやZshのような言語で、コードのビルド、デプロイ、検証、テストを行うためのかなりの量の必須ロジックがあると思います。あなたがツールの言語に慣れていないなら、それを簡単に読んだり改善したりすることはできません。あなたは、コードが実行されるリモートサーバーにどのように振る舞うかを指示できるかもしれませんが、あなたが作業しているコンピュータに、リンティングやテストを並列で実行する方法を指示することはできません。それは残念なことです!
ここで少し寄り道しましょう:なぜ、これほど多くのスクリプトが、チームが使用する主要な言語ではない言語で書かれているのでしょうか?コマンドを簡単に連携させるために設計された言語で、コマンドを連携させるスクリプトを書く方が、しばしばより人間工学的であると私は考えています。テストが失敗するまで実行する非常に簡単な例を見てみましょう。
while pnpm exec mocha ./pathToFile.test.ts; do true; done
この構文には明らかに批判すべき点がありますが、NodeJSでの見た目を見てみましょう。
const { execSync } = require("child_process");
while (true) {
try {
execSync(`pnpm exec mocha ./pathToFile.test.ts`, { stdio: "inherit" });
} catch (err) {
console.error("failed", err);
break;
}
}
ここには多くの粗削りな点や落とし穴がありますが、個人的にはシェルの方が簡単だと思います!ファイルを作成したり、child_processをrequireしたり、出力を表示するために{ stdio: "inherit" }を設定したりすることを心配する必要はありません。そして、これはパイプで複数のプログラムを連携させたり、出力をキャプチャしたり、一時ファイルを使用したりすることさえしない、非常に単純な例です!
💡 これは、ビルドスクリプトのためにBashやZshなどの言語で書くことに甘んじる必要があるという意味ではありません!JavaScriptをよく知っているチームにとって、私が楽しんでいるツールの1つはzxです。これらのスクリプトを非常に人間工学的に書き、保守できると思います。RubyとPythonはどちらもNodeJSよりも簡単ですが、このような簡単なスクリプトを書くにはさらに多くの儀式を必要とする言語がたくさんあると思います。確かに、シェルスクリプトがビルドスクリプトにとって常に簡単であると主張しているわけではありません!問題が単純で、2つのプログラムを連携させるだけであれば、BashやZshのようなツールは非常に人間工学的だと感じられます。より洗練されたロジックやデータ型が必要になったら、より洗練されたロジックやデータ型を表現(そしてテスト!)しやすくする言語を選択したくなるでしょう。シェル言語でビルドスクリプトが書かれていることに不満を言う多くのエンジニアは、実際には別の言語に変換しようとしたことがないのではないかと推測します。
構文(潜在的に)がより複雑であるという aside として、「シェルスクリプトを書くことを学ぶ」ことの大きな部分は、実際には構文ではありません。コマンドを連携させるスクリプトを変換しても、連携させているコマンドがどのように動作するかを実際には知らない場合、結果のスクリプトも同様に理解不能になる可能性が高いです。シェルを知ること、つまりコンピュータに指示を出すことができるようになることは、達成したいことを行うプログラムの知識に大きく依存します!
シェルを知ることは、構文が20%で、良いツールボックスを持っていることが80%だと主張します。
fzfを知っていれば、インタラクティブなファジー検索でクイックユーティリティを構築できます。(例:git checkout $(git branch --sort=-committerdate | fzf) は、ブランチをファジー選択できます。)
tldrまたはegを知っていれば、このリストにある他のコマンドの使用例を呼び出すことができます。
rsyncを知っていれば、変更されたファイルをより高速なリモートサーバーにコピーして、重くて遅い処理を実行できます。
xargsを知っていれば、コマンドを段階的に構築し、作業を並列化できます。
sed -iまたはast-grepを知っていれば、多数のファイルにわたる複雑なパターンを素早く書き直すことができます。
direnvを知っていれば、コードベースでコマンドを実行するすべての人が正しい環境変数を設定していることを確認できます。
duckdbを知っていれば、より大きなスクリプトの一部として、ローカルでCSVおよびJSONファイルをクエリするためにSQLを記述できます。
ghを知っていれば、PRを確認したり、CLIから新しいPRを開いたりするスクリプトを構築できます。
ngrokを知っていれば、ローカルポートを素早く提供して、別のマシンでテストできます。
あなたが学ぶ各追加プログラムは、あなたがすでに知っている他のすべてのプログラムと使用できるため、あなたの能力をさらに拡大します。
私はシェルスクリプトの専門家とはほど遠い存在であり、それを深く知っている人々にはひどいものですが、プログラムを連携させるのに十分なシェルの構文を知っていること、そして実際に連携させたいプログラムを十分に知っていることから、かなりの価値を得ています。
コンピュータに指示を出すのは素晴らしいことです!
このスクリプトは善意で書かれましたが、ifの主なモードがコマンドを取ることを知らなかったため、過度に複雑でした。[[(またはtest)は単なる特別なコマンドです。これは、ifチェックが単に! npm installになることを意味します。このアプローチでは、許可するために+eを設定する必要はありません。