※ この記事で紹介しているコマンドやワンライナーはすべて、Ubuntu環境で実践したものです。Windows環境をお使いの場合は、WSLなどのLinux環境上でお試しください。
はじめに
2年目エンジニアのRabbit_booKと申します。
開発部門に配属されてから、ちょうど1年が経とうとしています。
思えば私が初めてターミナルの操作をしたのは昨年6月、開発部門研修のはじめにPowershellでPC端末の名称を変更した時でした。
やっとコマンドラインの操作も身についてきたところですが、まだまだもっと使いこなせる余地があると感じる出来事があったので、その気付きをまとめてみたいと思います。
この記事が役に立つかもしれない人
- コマンドラインの操作はそこそこやったことある
-
cd、ls、rmとかなら使いこなせる - ベテランの人が書いてるめっちゃ長いワンライナーは、正直何をやっているのかわからない
ワンライナーを使ったらログの検証が爆速で終わった話
やりたかったこと
古いログを削除するジョブの改修を行っており、その検証の一環として、実行ログに出る「削除したログファイルの容量」が実体と一致しているか確認する必要がありました。
- ログの形式
[DRY-RUN] Would delete: /var/lib/jenkins/jobs/XXXXXXXX/builds/1 (Size: 3.7 MB)
- 当初やろうとしていた方法
ログから削除対象のディレクトリパスをコピーし、サーバー内部で du {ディレクトリ} する
[この方法のここがダメ]
- ログに出る削除対象ディレクトリは50~70件くらいあるので、手間がかかりすぎる
- まとまった出力にならないので、証跡としてわかりやすく残すのが難しい
- コピペ回数が多いので、ミスのリスクが上がる
- 生成AIが提案した方法
grep "Would delete:" jenkins_dryrun.log | head -n 10 | while read -r line; do
echo "=========================================="
echo "【Jenkinsログ】: $line"
# ログからパスを抽出してduを実行
path=$(echo "$line" | awk '{print $4}')
echo -n "【実際の du 】: "
du -sh "$path" 2>/dev/null || echo "パスが見つかりません"
done
というコマンドを実行することで、以下のような出力が得られます。
==========================================
【Jenkinsログ】: [DRY-RUN] Would delete: /var/lib/jenkins/jobs/.../builds/1 (Size: 3.7 MB)
【実際の du 】: 3.7M /var/lib/jenkins/jobs/.../builds/1
==========================================
【Jenkinsログ】: [DRY-RUN] Would delete: /var/lib/jenkins/jobs/.../builds/2 (Size: 4.1 MB)
【実際の du 】: 4.1M /var/lib/jenkins/jobs/.../builds/2
この方法に変えたことで、目視チェックの手間が減っただけでなく、出力をそのままテキストファイルに保存すれば検証のエビデンスとして扱えるようになり、作業がかなり楽になりました。
でも丸投げじゃダメかも
DRY_RUNを外して実行した際、ログのパターンが以下の様に変わってしまいました。
Deleted: /var/lib/jenkins/jobs/.../builds/1 (Size: 3.7 MB)
[DRY-RUN] Would delete: が Deleted:になっています。
最初はこれを深く考えず、先程までと同じワンライナーを投げてみました。
すると失敗し、「パスが見つかりません」と表示されてしまいます。
「よく見たらログの出方が変わってる、だから拾えないのか」と気付いて修正方法を考えました。
(ここもAIに再度投げてコマンドを出力させてもよいですが、軽微な修正だったためせっかくだしと考えてみました)
「そもそもどうやってパスを抜いてるんだろう? 4つ目の文字列と指定しているのかな?」→awk '{print $4}'っていうのがそれっぽい。
「じゃあ、DRY-RUNを外したときは文字列が2つ減ってるから、2つ目の文字列を指定する意味でawk '{print $2}'にしてみたらいけるか...?」 → いけた!!
またここで、awkコマンドはめっちゃ便利なのでは?と気づき、使い方を軽く調べて覚えておこうとも思いました。
awkコマンドのような最低限の知識を持つことで、0→1はAIに任せつつ、必要に応じてアレンジしながら自分の好きな出力を得る方向でもっと活用できそうです。
生成AI時代のワンライナーとの付き合い方
いきなり複雑なワンライナーを自在に書けるようになることを目指すより、まずは必要なときにAIを使って効率化し、そのうえで自分でも少しずつ仕組みを理解していく方が、自分には合っていると感じています。個人的に、そこを目指すよりも、生成AIの手を借りながら効率化を図り、浮いたリソースを他の開発業務に充てる方が生産性が高いと感じており、また一つの技術を極める職人型よりは、視野を広く持って浅く広い知識を身につけていきたいという方向性を持っているためです。
とはいえ、完全にAIへ丸投げでは今回のようなトラブルに対応できません。AIを活用しつつ自分の手札を増やしていくためには、「シェルを使えば、どういうことができるのか」という全体像というか、地図的な知識を持っておくことが重要だと感じました。
なんとなく覚えておくと便利そうな、定番っぽいコマンドや技
今回の件を経て、以下の要素を知っておくだけでも「AIが何をやっているか」を解読するヒントになると感じました。
-
|(パイプ): 左側のコマンドの出力結果を、右側のコマンドの入力としてそのまま渡す。コマンド同士を繋ぐ接着剤 -
grep: 大量の行から、特定の文字列が含まれる行だけを絞り込む -
head: 最初の数行だけを切り出す(head -n 10なら最初の10行)。まずは数件だけでテストしたい時に便利 -
awk: 行をスペースや特定の文字で分割して、指定した位置の文字列だけを抜き出す(今回のパス抽出の主役) -
while read: 渡されたデータを1行ずつ読み込んで、ループ処理を行う
おわりに
生成AIの普及によってあらゆる領域で言われていることではありますが、大切なのは「地図的な知識を身につけた上で、やりたいことを正確に言語化し、AIが出してきた出力を自分の目で検証することを怠らないこと」です。
完璧なシェル芸人にはなれずとも、このスタンスを持っていれば、業務に必要な「そこそこ使えるワンライナー」を「そこそこスピーディに」用意できるようになり、日々の開発をちょっとずつ楽にしていけるのではないかと思っています。