<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>インフラ・クラウド・OS・ツール on AIによる技術記事 備忘録</title><link>https://ai.hack-le.com/categories/%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89os%E3%83%84%E3%83%BC%E3%83%AB/</link><description>Recent content in インフラ・クラウド・OS・ツール on AIによる技術記事 備忘録</description><generator>Hugo -- gohugo.io</generator><language>ja</language><lastBuildDate>Wed, 04 Nov 2026 09:21:25 +0900</lastBuildDate><atom:link href="https://ai.hack-le.com/categories/%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89os%E3%83%84%E3%83%BC%E3%83%AB/index.xml" rel="self" type="application/rss+xml"/><item><title>FFmpegで動画のダウンサンプリング・リサイズと同時に再生速度を倍速にする方法</title><link>https://ai.hack-le.com/ffmpeg-downsample-resize-speed/</link><pubDate>Wed, 04 Nov 2026 09:21:25 +0900</pubDate><guid>https://ai.hack-le.com/ffmpeg-downsample-resize-speed/</guid><description>&lt;p&gt;FFmpegを用いて動画のファイルサイズを削減したりプレビュー用の軽量な動画を作成したりする際、フレームレートの引き下げ（ダウンサンプリング）と解像度の縮小（スケールダウン）を組み合わせる手法がよく用いられます。たとえば、入力動画 &lt;code&gt;input.mov&lt;/code&gt; を10fpsに間引きつつ横幅を800ピクセルに縮小し、音声を除去して &lt;code&gt;output.mp4&lt;/code&gt; へ出力する場合、以下のようなコマンドがベースとなります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -i input.mov -vf &lt;span class="s2"&gt;&amp;#34;fps=10,scale=800:-2&amp;#34;&lt;/span&gt; -c:v libx264 -crf &lt;span class="m"&gt;26&lt;/span&gt; -preset slow -an output.mp4&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この一連の変換処理に加えて、映像の再生速度を2倍速などに変更したい場合、既存のビデオフィルタ（&lt;code&gt;-vf&lt;/code&gt;）にタイムスタンプを制御するフィルタを追加することで、&lt;strong&gt;1回のエンコード処理で速度変更まで完結させる&lt;/strong&gt;ことが可能です。&lt;/p&gt;&#10;&lt;h2 id="再生速度の変更を追加したffmpegコマンド"&gt;再生速度の変更を追加したFFmpegコマンド&#10;&lt;/h2&gt;&lt;p&gt;元の変換処理に2倍速の処理を組み込むには、ビデオフィルタの先頭に &lt;code&gt;setpts&lt;/code&gt; フィルタを追加します。具体的なコマンドは以下の通りです。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -i input.mov -vf &lt;span class="s2"&gt;&amp;#34;setpts=0.5*PTS,fps=10,scale=800:-2&amp;#34;&lt;/span&gt; -c:v libx264 -crf &lt;span class="m"&gt;26&lt;/span&gt; -preset slow -an output.mp4&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各オプションの役割は以下の通りです。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-vf &amp;quot;setpts=0.5*PTS,fps=10,scale=800:-2&amp;quot;&lt;/code&gt; : 映像を2倍速にし、フレームレートを10fpsに変換したうえで、アスペクト比を維持しながら横幅800ピクセル（高さは2の倍数に自動調整）へ縮小します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-c:v libx264 -crf 26 -preset slow&lt;/code&gt; : H.264コーデックを使用し、品質基準（CRF値26）と圧縮効率（slow）を指定してエンコードします。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-an&lt;/code&gt; : 音声トラックを出力から除外します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="setptsフィルタによるタイムスタンプ制御の仕組み"&gt;setptsフィルタによるタイムスタンプ制御の仕組み&#10;&lt;/h2&gt;&lt;p&gt;FFmpegにおける &lt;code&gt;setpts&lt;/code&gt; は、映像の各フレームが持つPTS（Presentation Timestamp：表示タイムスタンプ）を書き換えるフィルタです。動画プレイヤーは各フレームに記録されたPTSを参照して表示タイミングを決定するため、&lt;strong&gt;各フレームのタイムスタンプの間隔を縮める&lt;/strong&gt;ことで再生速度を速めることができます。&lt;/p&gt;&#10;&lt;p&gt;元の映像を $N$ 倍速にする場合、新しいタイムスタンプ $\text{PTS}_{\text{new}}$ を求める計算式は以下のようになります。&lt;/p&gt;&#10;&lt;p&gt;$$\text{PTS}_{\text{new}} = \frac{1}{N} \times \text{PTS}$$&lt;/p&gt;&#10;&lt;p&gt;2倍速（$N = 2$）にする場合は $\frac{1}{2} = 0.5$ となるため &lt;code&gt;setpts=0.5*PTS&lt;/code&gt; と記述します。同様に、3倍速（$N = 3$）にしたい場合は &lt;code&gt;setpts=(1/3)*PTS&lt;/code&gt;、4倍速（$N = 4$）にしたい場合は &lt;code&gt;setpts=0.25*PTS&lt;/code&gt; と指定することで、任意の再生速度へ変更できます。反対に $0.5$ 倍速のスロー再生にしたい場合は $N = 0.5$ を代入し、タイムスタンプを2倍に引き伸ばす &lt;code&gt;setpts=2.0*PTS&lt;/code&gt; を指定します。&lt;/p&gt;&#10;&lt;h2 id="ビデオフィルタの適用順序と音声トラックの扱い"&gt;ビデオフィルタの適用順序と音声トラックの扱い&#10;&lt;/h2&gt;&lt;p&gt;複数のビデオフィルタをカンマ区切りで繋げた場合、FFmpegは記述された&lt;strong&gt;左から順番にフィルタ処理を適用する&lt;/strong&gt;という仕様を持っています。今回のコマンドにおいて &lt;code&gt;setpts=0.5*PTS&lt;/code&gt; を &lt;code&gt;fps=10&lt;/code&gt; の前に配置しているのは、倍速化によって時間軸が圧縮された後の映像に対してフレームレートの間引きを行うためです。&lt;/p&gt;&#10;&lt;p&gt;先に &lt;code&gt;setpts=0.5*PTS&lt;/code&gt; で元の映像を2倍速に圧縮し、その直後に &lt;code&gt;fps=10&lt;/code&gt; を適用することで、出力される2倍速の動画は正確に秒間10フレームへ調整されます。仮に順序を逆にして &lt;code&gt;fps=10,setpts=0.5*PTS&lt;/code&gt; と記述した場合、先に秒間10フレームへ間引かれた映像のタイムスタンプが後から半分に圧縮されるため、結果として秒間20フレームの映像が出力されてしまいます。意図したフレームレートとファイルサイズを得るためには、&lt;strong&gt;時間軸の操作をフレームレート変換の前に置く&lt;/strong&gt;ことが重要です。&lt;/p&gt;&#10;&lt;p&gt;また、通常FFmpegで動画の再生速度を変更する際は、映像用の &lt;code&gt;setpts&lt;/code&gt; とは別に、音声用の &lt;code&gt;atempo&lt;/code&gt; フィルタを用いて音声の再生速度も同期させる必要があります。しかし、今回のコマンドでは &lt;code&gt;-an&lt;/code&gt; オプションによって&lt;strong&gt;音声トラック自体が削除されている&lt;/strong&gt;ため、音声フィルタの追加や映像とのズレを考慮する必要はなく、ビデオフィルタの記述変更のみで処理が成立します。&lt;/p&gt;&#10;</description></item><item><title>なぜyt-dlpは違法として排除されないのか——技術と法、巨大プラットフォームが交錯する「冷戦」の構造</title><link>https://ai.hack-le.com/%E3%81%AA%E3%81%9Cyt-dlp%E3%81%AF%E9%81%95%E6%B3%95%E3%81%A8%E3%81%97%E3%81%A6%E6%8E%92%E9%99%A4%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B-%E6%8A%80%E8%A1%93%E3%81%A8%E6%B3%95-%E5%B7%A8%E5%A4%A7%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%8C%E4%BA%A4%E9%8C%AF%E3%81%99%E3%82%8B-%E5%86%B7/</link><pubDate>Fri, 30 Oct 2026 12:52:20 +0000</pubDate><guid>https://ai.hack-le.com/%E3%81%AA%E3%81%9Cyt-dlp%E3%81%AF%E9%81%95%E6%B3%95%E3%81%A8%E3%81%97%E3%81%A6%E6%8E%92%E9%99%A4%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B-%E6%8A%80%E8%A1%93%E3%81%A8%E6%B3%95-%E5%B7%A8%E5%A4%A7%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%8C%E4%BA%A4%E9%8C%AF%E3%81%99%E3%82%8B-%E5%86%B7/</guid><description>&lt;p&gt;通信環境が不安定な場所でのオフライン視聴や、手元でのアーカイブ作成、さらには音声認識AIを用いた文字起こしなど、コマンドラインツールの &lt;code&gt;yt-dlp&lt;/code&gt; が果たしている実用的な役割は極めて大きいと言えます。一方で、広告収益や有料サブスクリプションを基盤とする動画プラットフォーム側から見れば、こうしたダウンロードツールの存在はビジネスモデルと真っ向から対立するものです。&lt;/p&gt;&#10;&lt;p&gt;それにもかかわらず、なぜ &lt;code&gt;yt-dlp&lt;/code&gt; は違法ツールとして完全に排除されることなく、現在もオープンソースとして公に開発・配布が続けられているのでしょうか。単に「まだ裁かれていないだけ」なのか、それとも明確な法的根拠が存在するのか。その背景を紐解くと、著作権法の建付けやプラットフォーム側の経済合理性、そして技術と政治が水面下で繰り広げる激しい力の鍔迫り合いが見えてきます。&lt;/p&gt;&#10;&lt;h2 id="デュアルユース性と技術的保護手段を巡る法的建付け"&gt;デュアルユース性と技術的保護手段を巡る法的建付け&#10;&lt;/h2&gt;&lt;p&gt;あるソフトウェアの提供自体が違法とみなされるか否かを分ける最大の基準は、そのツールに&lt;strong&gt;実質的な非侵害用途が存在するか&lt;/strong&gt;という点にあります。これは米国のソニー・ベータマックス判決などに由来する法理であり、著作権侵害にも使われ得るが合法的な用途も広く存在する「デュアルユース（両用）技術」は、ツールの存在そのものを一律に違法とすることが極めて困難になります。実際に &lt;code&gt;yt-dlp&lt;/code&gt; には、以下のような明確に正当な利用目的が存在します。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;クリエイティブ・コモンズやパブリックドメインとして公開されている動画・音声の取得&lt;/li&gt;&#10;&lt;li&gt;コンテンツ制作者自身による、自らがアップロードしたオリジナルデータのバックアップ&lt;/li&gt;&#10;&lt;li&gt;配信者がダウンロードを明示的に許可している素材の取得&lt;/li&gt;&#10;&lt;li&gt;政府や自治体の記者会見動画などを取得し、ローカル環境の &lt;code&gt;Whisper&lt;/code&gt; 等を用いてテキスト化する情報解析やアクセシビリティ確保の作業&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;特に最後の「公的情報の文字起こし」のような用途は、法的にも倫理的にも強い正当性を持ちます。日本の著作権法第13条や第40条では、国の広報資料や政治上の演説・会見について広く国民に伝達されるべき性質から利用の自由が認められており、さらに第30条の4では&lt;strong&gt;情報解析を目的とする複製は著作権者の許諾なく行える&lt;/strong&gt;ことが明文で定められています。本来であれば発信元である行政機関などが提供すべきテキストデータを、ユーザー側が自前で代替処理しているに過ぎず、こうした用途を支えるツールを一律に封殺することは法理上も無理が生じます。&lt;/p&gt;&#10;&lt;p&gt;また、著作権法において最も厳しい規制対象となるのは、日本の著作権法第30条第1項第2号や米国DMCA（デジタルミレニアム著作権法）第1201条が定める&lt;strong&gt;技術的保護手段の回避&lt;/strong&gt;です。Netflixや有料レンタル動画などで使われている &lt;code&gt;Widevine&lt;/code&gt; などの本格的なDRM（デジタル著作権管理）は、ストリーム自体が暗号化されており、これをクラックして復号する行為やツールの提供は明確に違法となります。&lt;/p&gt;&#10;&lt;p&gt;しかし、&lt;code&gt;yt-dlp&lt;/code&gt; はこうしたDRMで暗号化されたコンテンツを解除する機能を意図的に排除しています。一般公開されている無料動画は、あらゆるブラウザで再生できるよう、データそのものは暗号化されずに &lt;code&gt;HLS/DASH&lt;/code&gt; などの形式で分割送信されています。&lt;code&gt;yt-dlp&lt;/code&gt; が行っているのは、JavaScriptの難読化処理や署名トークン（シグネチャ）を解決して再生用のURLを特定・結合する処理であり、技術的には&lt;strong&gt;ブラウザが再生時に行っている &lt;code&gt;HTTP/HTTPS&lt;/code&gt; リクエストと同一の手順をコマンドラインでエミュレートしているだけ&lt;/strong&gt;という建付けをとっています。&lt;/p&gt;&#10;&lt;p&gt;2020年には、全米レコード協会（RIAA）が前身プロジェクトである &lt;code&gt;youtube-dl&lt;/code&gt; に対し、シグネチャの解決が技術的保護手段の回避にあたるとしてGitHubに削除要請を行う事件が起きました。しかし、電子フロンティア財団（EFF）の弁護団が「シグネチャの解決は暗号の解読ではなく、誰でもアクセス可能な平文ストリームの取得手順に過ぎない」と反論し、GitHub側もこれを受理してリポジトリを復活させています。一方で、ドイツの裁判所ではこのシグネチャ制御も実効性のある保護手段とみなされ、ホスティング事業者に対する差止請求が認められるなど、司法判断は国によって割れており、法的な境界線上で今なお拮抗が続いているのが実態です。&lt;/p&gt;&#10;&lt;p&gt;なお、ユーザーが動画を保存する行為そのものについては、違法アップロードされた動画と知りながらダウンロードする行為は違法となるものの、公式に無料公開されている正規の動画を個人で楽しむために保存する行為は、日本の著作権法第30条第1項が定める&lt;strong&gt;私的使用のための複製&lt;/strong&gt;として合法とされています。YouTubeの利用規約ではダウンロード行為が明確に禁止されていますが、これはあくまでサービス提供者と利用者間の&lt;strong&gt;民事上の契約違反&lt;/strong&gt;であり、直ちに国の法律を犯す犯罪（違法行為）とイコールになるわけではありません。&lt;/p&gt;&#10;&lt;h2 id="巨大プラットフォームの経済合理性と正面衝突を避ける力学"&gt;巨大プラットフォームの経済合理性と正面衝突を避ける力学&#10;&lt;/h2&gt;&lt;p&gt;法的なグレーゾーンや防御論理があるとはいえ、数兆ドル規模の資本を持つ巨大プラットフォームが本気で法廷闘争を仕掛ければ、個人の開発者コミュニティを圧倒することは不可能ではないようにも思えます。それでもYouTube側が全面的な法的排除に踏み切らない背景には、冷徹な損益計算と、自らが抱える歴史的・構造的な脆弱性があります。&lt;/p&gt;&#10;&lt;p&gt;第一に、ターゲット層の規模と費用対効果の問題です。&lt;code&gt;yt-dlp&lt;/code&gt; のようなコマンドラインツールを導入し、&lt;code&gt;ffmpeg&lt;/code&gt; などの依存パッケージを管理して使いこなすユーザーは、全利用者のうちごく一部の技術層（マニア層）に限られます。大多数の一般ユーザーは公式アプリで広告を見るか、YouTube Premiumに課金してオフライン保存機能を利用するため、全体の広告収益に対する実質的な被害は極めて軽微です。仮に法廷で徹底的に争った場合、EFFなどの強力な支援団体と全面対決することになり、万が一にも最高裁などで&lt;strong&gt;一般公開されている動画ストリームのスクレイピングやダウンロードは完全に合法である&lt;/strong&gt;という確定判例が出てしまえば、利用規約の優位性すら揺らぎ、事業そのものに致命的なリスクを招きかねません。&lt;/p&gt;&#10;&lt;p&gt;第二に、プラットフォーム自身の歴史的経緯と基幹事業への「ブーメラン」となるリスクです。YouTubeは創業当初、ユーザーが無許諾で投稿したテレビ番組や音楽クリップなどの海賊版コンテンツによって爆発的な成長を遂げました。当時の巨額訴訟から同社を守ったのは、米国DMCA第512条のセーフハーバー条項、すなわち&lt;strong&gt;場やツールを提供する者はユーザーの個別の侵害行為に対して一律の責任を負わない&lt;/strong&gt;という法理でした。自らがその法理を最大限に活用して生き残った以上、同じ論理で防御を固めるオープンソースツールを正面から否定することには自己矛盾が伴います。&lt;/p&gt;&#10;&lt;p&gt;さらに決定的なのは、親会社であるGoogleの基幹事業との整合性です。Googleの検索エンジンやAIモデルの学習は、世界中のWebサーバーから &lt;code&gt;robots.txt&lt;/code&gt; の解釈を広げつつ大量のデータをクローリング・複製することで成り立っています。もしYouTubeが「サーバー側が意図した公式ブラウザ以外の手段で、公開プロトコルから平文データを自動取得・解析するソフトウェアは違法である」という法理を裁判で確立させてしまえば、それは&lt;strong&gt;Google自身のWebクローラーやデータ収集活動の合法性を根底から否定する諸刃の剣&lt;/strong&gt;となって跳ね返ってきます。&lt;/p&gt;&#10;&lt;h2 id="法の限界とコードによる非対称な実力行使"&gt;法の限界とコードによる非対称な実力行使&#10;&lt;/h2&gt;&lt;p&gt;このように法廷での全面戦争が双方にとって得策ではない状況下において、主戦場は「法」から「技術」へと移行しています。法学者のローレンス・レッシグは、サイバー空間を規制する4つの要素として「法（Law）」「規範（Norms）」「市場（Market）」「アーキテクチャ／コード（Code）」を挙げましたが、&lt;code&gt;yt-dlp&lt;/code&gt; を巡る攻防はまさに&lt;strong&gt;法や規範による統制が限界を迎え、コード同士の直接的な実力行使に移行した状態&lt;/strong&gt;を体現しています。&lt;/p&gt;&#10;&lt;p&gt;YouTube側は法的措置の代わりに、シグネチャ生成アルゴリズムの頻繁な変更、非公式クライアントに対する通信速度の極端な制限（スロットリング）、IP単位の遮断や &lt;code&gt;PO-Token&lt;/code&gt;（Proof of Origin）の導入など、技術的な仕様変更によって定期的に &lt;code&gt;yt-dlp&lt;/code&gt; を動作不能に追い込む消耗戦を仕掛けています。開発者側に継続的なメンテナンスコストを押し付けることで、ツールの利用ハードルを高く維持し、一般層へ拡散するのを防ぐという防衛策が最も経済合理的だからです。&lt;/p&gt;&#10;&lt;p&gt;これに対し、&lt;code&gt;yt-dlp&lt;/code&gt; の開発コミュニティは、JavaScriptインタープリタによる動的なシグネチャ解決や、チャンク分割取得、プレイヤーパラメータの偽装、ブラウザからのCookieインポート機能の実装など、リバースエンジニアリングによる対抗措置を即座に講じています。ここでは裁判所の命令ではなく、&lt;strong&gt;サーバーが要求する暗黙のプロトコルをクライアント側が解析して突破できるか否かという物理的・技術的現実&lt;/strong&gt;のみがルールを決定しています。&lt;/p&gt;&#10;&lt;p&gt;この鍔迫り合いが持続する本質的な理由は、両者の非対称な構造にあります。YouTubeは公開サービスである以上、正規のブラウザやアプリに対して最終的にストリームデータを平文で届けざるを得ないという「集中型プラットフォームの弱点」を抱えています。クライアントにデータを届ける手順が存在する限り、それを模倣される余地を原理的にゼロにはできません。一方で、オープンソース側は特定の企業ではなく世界中に分散した有志の集合体であり、仮に特定のリポジトリが閉鎖されても瞬時にフォーク（複製）が立ち上がるという「分散型の強靭性」を持っています。&lt;/p&gt;&#10;&lt;h2 id="囲い込みとオープンプロトコルの冷戦"&gt;囲い込みとオープンプロトコルの冷戦&#10;&lt;/h2&gt;&lt;p&gt;ここまでの構造を俯瞰すると、表向きに語られる「建前」と、水面下で機能している「本音（現実の力学）」の鮮やかな対比が浮かび上がります。&lt;/p&gt;&#10;&lt;p&gt;プラットフォーム側は「著作権の保護」や「クリエイターの収益還元」を建前として掲げますが、実質的な目的はユーザーの滞在時間や広告接触、トラフィックデータの私有化（囲い込み）にあり、自社のクローラー事業への波及を恐れて決定的な法的攻撃を手控えています。対するオープンソース側も「Webの相互運用性」や「アクセシビリティの確保」という理念を掲げつつ、実態としてはDMCA違反の直撃を避けるためにDRM解除コードを厳格に排除し、「あくまでブラウザの通信を模倣しているだけである」という法的な防衛線を精巧に維持しながら開発を続けています。&lt;/p&gt;&#10;&lt;p&gt;この現象のさらに根底には、&lt;strong&gt;近代法が前提としてきた所有権や契約の概念が、インターネットのプロトコルという物理層に追いついていない&lt;/strong&gt;という構造的な歪みがあります。公開された通信経路を通じて送信されるデータパケットは、電気信号や光信号という物理現象として受信側のハードウェアに到達します。一度自分の端末に届いた信号を、揮発性のメモリ上で再生して捨てるか、ストレージに書き込んで永続化するか、あるいはAIモデルに入力して文字に変換するかという処理は、本来であれば受信端末の所有権に基づく物理的自由の領域に属するものです。&lt;/p&gt;&#10;&lt;p&gt;プラットフォーム側は利用規約という私的な契約の網を被せることで、この受信後の処理にまで制限を加えようと試みます。これに対し、&lt;code&gt;yt-dlp&lt;/code&gt; はオープンな通信プロトコルを処理しているだけであるという技術的建前を盾にして、その囲い込みを実力で無効化し続けています。すなわち、&lt;code&gt;yt-dlp&lt;/code&gt; が違法として排除されずに存在し続けている現状は、単なる法の抜け穴ではなく、&lt;strong&gt;私有化された巨大資本のプラットフォームと非中央集権的なオープンプロトコルが、互いに決定打を欠いたまま高度な均衡を保っているインターネット上の冷戦状態&lt;/strong&gt;そのものであると言えます。&lt;/p&gt;&#10;</description></item><item><title>DeepSeek Harness入門：Clineとの違いからリモート実行環境の構築・トラブルシュートまで</title><link>https://ai.hack-le.com/deepseek-harness%E5%85%A5%E9%96%80%EF%BC%9Acline%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84%E3%81%8B%E3%82%89%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83%E3%81%AE%E6%A7%8B/</link><pubDate>Wed, 28 Oct 2026 01:57:29 +0900</pubDate><guid>https://ai.hack-le.com/deepseek-harness%E5%85%A5%E9%96%80%EF%BC%9Acline%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84%E3%81%8B%E3%82%89%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83%E3%81%AE%E6%A7%8B/</guid><description>&lt;p&gt;自律型AIエージェントの実行環境として登場した &lt;strong&gt;DeepSeek Harness&lt;/strong&gt;（CLI名：&lt;code&gt;dsh&lt;/code&gt;）は、これまでエディタ統合型ツールを利用してきた開発者にとって、運用の前提を大きく変える存在です。VSCodeと拡張機能の組み合わせ（Clineなど）による開発スタイルと何が異なるのか、その設計思想からローカルネットワーク越しの安全な運用環境の構築手順、初期導入時のトラブルシュートまでを論理的に解説します。&lt;/p&gt;&#10;&lt;h2 id="1-エージェントの実行台座ハーネスの概念とclineとの違い"&gt;1. エージェントの実行台座「ハーネス」の概念とClineとの違い&#10;&lt;/h2&gt;&lt;p&gt;工学において「ハーネス（Harness）」は本来、馬を御する馬具や電気配線を束ねるワイヤーハーネス、あるいはソフトウェアの &lt;strong&gt;テストハーネス&lt;/strong&gt;（テスト対象を包み込み、入力を与えて出力を観測する台座）を指す言葉です。&lt;/p&gt;&#10;&lt;p&gt;大規模言語モデル（LLM）は単体ではテキストの入出力を行う計算機構に過ぎず、ファイルを読み書きする権限もシェルを実行する手段も持ちません。エージェント工学におけるハーネスとは、モデルを作業環境（ファイルシステム、OS、シェル、ネットワーク）に接続し、その &lt;strong&gt;思考と実行の自律ループを制御・記録・検証するための外枠（実行・観測台座）&lt;/strong&gt; を意味します。&lt;/p&gt;&#10;&lt;p&gt;これまで広く使われてきた VSCode + Cline と DeepSeek Harness の決定的な違いは、その設計思想にあります。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;VSCode + Cline&lt;/strong&gt;：人間のエディタ操作に寄り添う「ペアプログラミング型」のアシスタントです。エディタ上で差分を目視確認しながら対話的にコードを修正する用途に適していますが、VSCodeのGUIセッションに強く依存し、履歴は一本道のチャットとして蓄積されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;DeepSeek Harness&lt;/strong&gt;：モデルの自律タスク実行と挙動検証を主眼に置いた「独立型テストベンチ」です。エディタから独立したプロセス（CLIおよびWeb UI）として動作し、エージェントの挙動を &lt;strong&gt;Trajectory（実行軌跡）&lt;/strong&gt; と呼ばれる構造化データとして記録します。過去の任意のステップに戻って別の指示を与える分岐実行（Fork）や、一連の実行ログをそのままトレースする完全再現（Replay）が可能です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-macosでのセットアップと運用設計の思想"&gt;2. macOSでのセットアップと運用設計の思想&#10;&lt;/h2&gt;&lt;p&gt;macOS上で動作させる場合、Node.js 22.19以上（または24系）の環境を用意し、作業対象のディレクトリから起動します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 環境変数の設定（~/.zshrc 等）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;DEEPSEEK_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sk-xxxxxxxxxxxxxxxxxxxxxxxx&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ワークスペースディレクトリで起動&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/project&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @deepseek-ai/dsh web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Web UIを開くと、VSCodeのような人間向けの対話型ターミナルが存在しないことに気づきます。これは制限ではなく、&lt;strong&gt;状態の再現性を担保するための意図的な設計&lt;/strong&gt; です。人間が裏で自由にシェルコマンドを叩いてファイルや環境の状態を変更してしまうと、Harnessが記録しているTrajectoryと実際のファイルシステムとの整合性が崩れ、過去ステップへの巻き戻しや分岐の正確性が失われます。そのため、すべてのコマンド実行はエージェントのツール呼び出しとして扱われ、人間はそれを承認（Approve）するかどうかを判断する形を取ります。&lt;/p&gt;&#10;&lt;p&gt;また、Harnessを利用する際は &lt;strong&gt;トークン消費の累積構造&lt;/strong&gt; を意識する必要があります。自律エージェントのコンテキスト長 $C_t$ は、ステップ数 $t$ に対し、初期プロンプト $I$、各ステップの思考 $T_i$、ツール実行ログやコマンド出力 $O_i$ の総和として累積します。&lt;/p&gt;&#10;&lt;p&gt;$$C_t = I + \sum_{i=1}^{t} (T_i + O_i)$$&lt;/p&gt;&#10;&lt;p&gt;巨大なテストログの出力やファイル全体の読み込みが発生すると、1回のリクエストで送信される入力トークンが急増します。タスクごとにセッションを細かく切り替えることや、DeepSeek Platform側のダッシュボードで利用上限額（Hard Limit）を事前に設定しておく運用が推奨されます。&lt;/p&gt;&#10;&lt;h2 id="3-セキュリティ境界の設計専用マシンとリモート運用の可能性"&gt;3. セキュリティ境界の設計：専用マシンとリモート運用の可能性&#10;&lt;/h2&gt;&lt;p&gt;Harnessは外部アクセス機能を持たないローカルWebサーバーとして動作しますが、外出先から利用するために Cloudflare Tunnel と Cloudflare Access（Zero Trust）を組み合わせる構成は非常に合理的です。ルーターのポート開放を行うことなく、Cloudflareのエッジで強固なゼロトラスト認証（Google認証やメールPIN）を通過した通信のみをローカルの &lt;code&gt;127.0.0.1:3080&lt;/code&gt; へ安全に転送できます。&lt;/p&gt;&#10;&lt;p&gt;しかし、エージェント環境のリモート常時稼働には固有のリスクが存在します。エージェントは「任意のシェルコマンド実行権限」を持つため、設定不備や不測の脆弱性が生じた際の影響範囲（Blast Radius）が、個人データや各種秘密鍵を保管しているメインの作業マシン全体に波及しかねません。&lt;/p&gt;&#10;&lt;p&gt;このリスクを根本的に排除するためには、使わなくなったPCやミニPC、隔離された仮想マシン（VM）を &lt;strong&gt;DeepSeek Harness専用マシン&lt;/strong&gt; として切り出し、メインの開発端末と物理的・論理的に分離するアプローチが極めて有効です。専用マシン上には必要最小限のリポジトリとAPIキーのみを配置し、万が一のインシデント時にもメインの環境を安全に保つ構成が取られます。&lt;/p&gt;&#10;&lt;h2 id="4-lan内別マシンwindowsからのアクセスと認証トークンの解決"&gt;4. LAN内別マシン（Windows）からのアクセスと認証トークンの解決&#10;&lt;/h2&gt;&lt;p&gt;家庭内やオフィス内のLANにおいて、Mac上で動くHarnessのWeb UIに対して別のWindowsマシンからアクセスしたい場合、SSHポートフォワーディングを利用するのが最も簡潔で安全です。&lt;/p&gt;&#10;&lt;p&gt;Windows 10/11には標準で OpenSSH クライアントが統合されているため、WSL2を起動する必要はありません。WSL2内部でSSHトンネルを張ると、仮想マシンのNATやlocalhostフォワーディングの不整合によってブラウザから通信が届かないトラブルの原因になりやすいため、&lt;strong&gt;WindowsネイティブのPowerShell&lt;/strong&gt; から直接コマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# WindowsのPowerShellで実行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -N -L 3080:127.0.0.1:3080 &amp;lt;Macのユーザー名&amp;gt;@&amp;lt;MacのローカルIP&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを維持した状態でWindowsのブラウザから &lt;code&gt;[http://127.0.0.1:3080](http://127.0.0.1:3080)&lt;/code&gt; にアクセスすると、次のようなエラーが表示されることがあります。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;code&gt;dsh web authentication required; reopen the URL printed by dsh web.&lt;/code&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;これは不具合ではなく、同一LAN内の他者やローカルの別プロセスによる不正操作（CSRF等）を防ぐための &lt;strong&gt;ワンタイム認証トークン仕様&lt;/strong&gt; によるものです。&lt;/p&gt;&#10;&lt;h3 id="解決手順"&gt;解決手順&#10;&lt;/h3&gt;&lt;p&gt;Mac側で &lt;code&gt;dsh web&lt;/code&gt; を起動した際、ターミナルの出力ログの末尾にクエリパラメータが付与されたURLが表示されています。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://127.0.0.1:3080/?token&lt;span class="o"&gt;=&lt;/span&gt;abcdef1234567890...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Windows側ブラウザのアドレスバーに、単なる &lt;code&gt;[http://127.0.0.1:3080](http://127.0.0.1:3080)&lt;/code&gt; ではなく、この &lt;strong&gt;&lt;code&gt;?token=...&lt;/code&gt; を含めた完全なURL&lt;/strong&gt; を入力して開くことで認証が完了し、以降は別マシンのブラウザからMac上のHarnessを安定して操作できるようになります。&lt;/p&gt;&#10;</description></item><item><title>自宅サーバー公開におけるルーティング設計：Cloudflare TunnelとCaddyの役割分担</title><link>https://ai.hack-le.com/%E8%87%AA%E5%AE%85%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E5%85%AC%E9%96%8B%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E8%A8%AD%E8%A8%88%EF%BC%9Acloudflare/</link><pubDate>Sun, 25 Oct 2026 22:30:33 +0900</pubDate><guid>https://ai.hack-le.com/%E8%87%AA%E5%AE%85%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E5%85%AC%E9%96%8B%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E8%A8%AD%E8%A8%88%EF%BC%9Acloudflare/</guid><description>&lt;p&gt;自宅サーバーで複数のWebアプリケーションをホストする際、外部公開手段としての &lt;strong&gt;Cloudflare Tunnel（&lt;code&gt;cloudflared&lt;/code&gt;）&lt;/strong&gt; 、ローカル環境用のリバースプロキシとしての &lt;strong&gt;Caddy&lt;/strong&gt;、そしてLAN内の名前解決を担う &lt;strong&gt;AdGuard Home&lt;/strong&gt; などのDNSサーバーを併用する設計は広く利用されています。&lt;/p&gt;&#10;&lt;p&gt;この構成を検討する際によく生じる疑問が、「外部からのアクセスは Caddy を経由させるべきなのか、それとも &lt;code&gt;cloudflared&lt;/code&gt; から直接各アプリケーションのポートへ向けるべきなのか」というルーティングの設計判断です。結論から言えば、通信プロトコルとしてはいずれの経路も正常に成立します。両者の違いは正誤ではなく、&lt;strong&gt;システムの単純性を取るか、ローカル側での制御の一元化を取るか&lt;/strong&gt;という設計原則のトレードオフにあります。&lt;/p&gt;&#10;&lt;h2 id="物理配置とネットワーク境界の前提"&gt;物理配置とネットワーク境界の前提&#10;&lt;/h2&gt;&lt;p&gt;構成を整理する上での大前提として、各コンポーネントがネットワーク上のどこに配置されているかを正確に把握する必要があります。&lt;/p&gt;&#10;&lt;p&gt;外部からのトラフィックを受ける最初の接点は、インターネット上に分散配置された &lt;strong&gt;Cloudflare Edge&lt;/strong&gt; です。外部ユーザーはこのエッジサーバーに対して HTTPS アクセスを行います。一方、 &lt;strong&gt;&lt;code&gt;cloudflared&lt;/code&gt; の実体はインターネット上ではなく、自宅LAN内のサーバー上で動作するデーモン&lt;/strong&gt;です。このデーモンが自宅内から Cloudflare Edge に向けて外向き（アウトバウンド）の安全なトンネル接続を確立し、外部からの要求を自宅ネットワーク内部へ引き込みます。&lt;/p&gt;&#10;&lt;p&gt;したがって、通信の物理的な境界線は「インターネット上の Cloudflare Edge」と「自宅LAN内の &lt;code&gt;cloudflared&lt;/code&gt;」の間に引かれます。その上で、引き込んだトラフィックを LAN 内でどう分配するかが設計の分岐点となります。&lt;/p&gt;&#10;&lt;div class="mermaid"&gt;&#10;graph TD&#10;subgraph &amp;#34;インターネット (WAN)&amp;#34;&#10;User_Ext[&amp;#34;外部ユーザー&amp;#34;]&#10;CF_Edge[&amp;#34;Cloudflare Edge&amp;#34;]&#10;end&#10;subgraph &amp;#34;自宅LAN&amp;#34;&#10;Tunnel[&amp;#34;cloudflared&amp;#34;]&#10;User_Int[&amp;#34;LAN内クライアント&amp;#34;]&#10;AGH[&amp;#34;AdGuard Home(スプリットDNS)&amp;#34;]&#10;Caddy[&amp;#34;Caddy(リバースプロキシ)&amp;#34;]&#10;App[&amp;#34;Webアプリケーション群&amp;#34;]&#10;end&#10;User_Ext --&amp;gt; CF_Edge&#10;CF_Edge Tunnel&#10;User_Int -.-&amp;gt; AGH&#10;AGH -.-&amp;gt; User_Int&#10;&lt;/div&gt;&#10;&lt;h2 id="caddy-を経由させる構成単一ゲートウェイ原則"&gt;Caddy を経由させる構成（単一ゲートウェイ原則）&#10;&lt;/h2&gt;&lt;p&gt;外部からの通信をすべて一度 Caddy に集約し、Caddy から各アプリケーションへ中継する構成です。この方式は、トラフィックの流入元が外部トンネルであれローカルWi-Fiであれ、すべてのアプリケーションの前段に Caddy を唯一の「内部ゲートウェイ」として配置するという思想に基づいています。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;外部: ユーザー -&amp;gt; Cloudflare Edge -&amp;gt; cloudflared -&amp;gt; Caddy -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内部: ユーザー -&amp;gt; (AdGuard Home で解決) -&amp;gt; Caddy -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="メリット"&gt;メリット&#10;&lt;/h3&gt;&lt;p&gt;この構成の最大の強みは、&lt;strong&gt;ルーティングとアクセスログのローカル一元化&lt;/strong&gt;にあります。&lt;code&gt;cloudflared&lt;/code&gt; 側の設定は「ドメイン全体の通信をすべてローカルの Caddy へ流す」という抽象的なルールのみで固定できます。これにより、新しくアプリケーションを追加・変更する際も、外部のトンネル設定に手を加える必要がなく、ローカルの &lt;code&gt;Caddyfile&lt;/code&gt; と内部 DNS レコードを更新するだけで作業が完結します。また、すべてのアクセスが Caddy を通過するため、ローカルサーバー単体で統一的なアクセスログを取得・監視することが可能です。&lt;/p&gt;&#10;&lt;h3 id="デメリットと注意点"&gt;デメリットと注意点&#10;&lt;/h3&gt;&lt;p&gt;この方式の課題は、&lt;strong&gt;二重リバースプロキシによる運用の複雑化&lt;/strong&gt;です。Cloudflare Edge で一度終端された HTTPS 通信が Caddy に渡されるため、プロキシヘッダーの適切な伝播が不可欠となります。具体的には、Caddy 側で &lt;code&gt;trusted_proxies&lt;/code&gt; などの設定を正しく行わないと、クライアントの送信元 IP アドレスが &lt;code&gt;cloudflared&lt;/code&gt; のローカル IP に上書きされたり、プロトコル（HTTP/HTTPS）の認識違いによって WordPress 等のアプリケーションでリダイレクトループが発生する原因になります。また、Caddy が停止した際に外部・内部双方の通信が同時にダウンするという、単一障害点（SPOF）を抱えることになります。&lt;/p&gt;&#10;&lt;h2 id="caddy-を経由させない構成疎結合最小ホップ原則"&gt;Caddy を経由させない構成（疎結合・最小ホップ原則）&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;cloudflared&lt;/code&gt; が備える Ingress ルールを用い、外部からの通信を Caddy を介さずに直接各アプリケーションのポート番号へフォワードする構成です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;外部: ユーザー -&amp;gt; Cloudflare Edge -&amp;gt; cloudflared -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内部: ユーザー -&amp;gt; (AdGuard Home で解決) -&amp;gt; Caddy -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="メリット-1"&gt;メリット&#10;&lt;/h3&gt;&lt;p&gt;この構成の根拠は、&lt;strong&gt;不要な中間レイヤーの排除&lt;/strong&gt;にあります。&lt;code&gt;cloudflared&lt;/code&gt; 自体がリバースプロキシとしての転送機能を備えているため、後段にさらに Caddy を挟むことは処理遅延と障害要因を増やすだけにすぎないという判断です。多段プロキシ構造を避けることで、前述したヘッダーの食い違いや SSL 終端に起因するリダイレクトトラブルのリスクを根本から排除できます。また、Caddy の設定ミスや障害が外部公開用エンドポイントに波及しません。&lt;/p&gt;&#10;&lt;h3 id="デメリットと注意点-1"&gt;デメリットと注意点&#10;&lt;/h3&gt;&lt;p&gt;一方で、&lt;strong&gt;ルーティング設定が2箇所に分散する&lt;/strong&gt;という管理上のコストが発生します。外部からのアクセス経路は Cloudflare 側（Zero Trust ダッシュボードまたはローカルの &lt;code&gt;config.yml&lt;/code&gt;）で定義し、LAN 内からのアクセス経路は &lt;code&gt;Caddyfile&lt;/code&gt; で個別に定義しなければなりません。ポート番号やコンテナの配置を変更した際に一方の更新を忘れると、「LAN内からは開けるが外部からは繋がらない」といった不整合が生じやすくなります。&lt;/p&gt;&#10;&lt;h2 id="運用における選択基準"&gt;運用における選択基準&#10;&lt;/h2&gt;&lt;p&gt;コミュニティや実際の運用環境における傾向を踏まえると、選択の基準は「管理するサービスの規模」と「ローカル完結の重要度」に集約されます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Caddy 経由が選ばれるケース&lt;/strong&gt;: 多数のコンテナやサービスを自宅内で常時稼働させており、AdGuard Home によるスプリットホライズンDNSを構築してLAN内からの高速な直接アクセスを維持したい環境。サービス追加のたびに外部トンネルの設定を弄る手間を減らし、ローカル側の設定ファイル群でインフラを一元管理したい場合に適しています。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Caddy 非経由（直接転送）が選ばれるケース&lt;/strong&gt;: 公開するサービスが少数（数個程度）に限定されている環境。Cloudflare Zero Trust の GUI 管理画面上でサブドメインの転送先とアクセス制御（Cloudflare Access 等による認証）をまとめて視覚的に管理したい場合や、多段プロキシに起因するネットワークトラブルの検証コストを最小限に抑えたい場合に適しています。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;どちらの構成を選択する場合であっても、ネットワークの物理的な境界と各プロキシが担う責務の境界を明確に定義することが、安定したセルフホスト運用の基盤となります。&lt;/p&gt;&#10;</description></item><item><title>EmacsでC-h（ヘルプ）を誤打したときに画面を元の状態へ戻す手順</title><link>https://ai.hack-le.com/emacs%E3%81%A7c-h%EF%BC%88%E3%83%98%E3%83%AB%E3%83%97%EF%BC%89%E3%82%92%E8%AA%A4%E6%89%93%E3%81%97%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E7%94%BB%E9%9D%A2%E3%82%92%E5%85%83%E3%81%AE%E7%8A%B6%E6%85%8B/</link><pubDate>Sun, 25 Oct 2026 22:21:46 +0900</pubDate><guid>https://ai.hack-le.com/emacs%E3%81%A7c-h%EF%BC%88%E3%83%98%E3%83%AB%E3%83%97%EF%BC%89%E3%82%92%E8%AA%A4%E6%89%93%E3%81%97%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E7%94%BB%E9%9D%A2%E3%82%92%E5%85%83%E3%81%AE%E7%8A%B6%E6%85%8B/</guid><description>&lt;p&gt;Emacsの操作中に &lt;code&gt;C-h&lt;/code&gt; を誤って押してしまい、意図せずヘルプ機能に入ってしまうケースは珍しくありません。この状況で混乱が生じやすい根本的な理由は、Emacsが現在 &lt;strong&gt;キー入力の待機中&lt;/strong&gt; なのか、それともすでに &lt;strong&gt;ヘルプ画面が展開された後&lt;/strong&gt; なのかによって、復帰に必要な操作のレイヤーが異なる点にあります。現在の状態を正しく判別できれば、迷わず元の編集状態へ復帰できます。&lt;/p&gt;&#10;&lt;h2 id="キー入力待ちの状態から中断する"&gt;キー入力待ちの状態から中断する&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;C-h&lt;/code&gt; を押した直後、画面最下部のミニバッファに &lt;code&gt;C-h-&lt;/code&gt; と表示されて後続のキー入力を待っている段階では、ヘルプのウィンドウ自体はまだ開かれていません。この状態はEmacsがコマンドの追加入力を受け付けている途中にすぎないため、キーシーケンスの中断コマンドを実行します。&lt;/p&gt;&#10;&lt;p&gt;ここで使用するのが &lt;strong&gt;&lt;code&gt;C-g&lt;/code&gt;&lt;/strong&gt; （&lt;code&gt;keyboard-quit&lt;/code&gt;）です。&lt;code&gt;C-g&lt;/code&gt; を入力すると進行中のコマンド受付が直ちに破棄され、ミニバッファに &lt;code&gt;Quit&lt;/code&gt; と表示されて元のバッファの編集状態に復帰します。&lt;/p&gt;&#10;&lt;h2 id="ヘルプ画面が表示された後に元の配置へ戻す"&gt;ヘルプ画面が表示された後に元の配置へ戻す&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;C-h&lt;/code&gt; に続いて何らかのキーを押してしまい、ウィンドウが2分割されて &lt;code&gt;*Help*&lt;/code&gt; バッファが展開された場合は、キー入力の中断ではなくウィンドウのレイアウトを戻す処理が必要になります。この段階では、カーソル（ポイント）がどちらのウィンドウに存在するかによって選択する操作が変わります。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ヘルプバッファ側にカーソルがある場合&lt;/strong&gt;: &lt;strong&gt;&lt;code&gt;q&lt;/code&gt;&lt;/strong&gt; （&lt;code&gt;quit-window&lt;/code&gt;）を押します。ヘルプ表示用のモードでは &lt;code&gt;q&lt;/code&gt; にウィンドウを閉じて直前の配置に戻す動作が割り当てられているため、1ストロークで元の状態に復帰します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;元の編集バッファ側にカーソルがある場合&lt;/strong&gt;: &lt;strong&gt;&lt;code&gt;C-x 1&lt;/code&gt;&lt;/strong&gt; （&lt;code&gt;delete-other-windows&lt;/code&gt;）を押します。現在カーソルが置かれているウィンドウ以外の分割画面が一括で非表示となり、編集画面が再び単一の全画面表示に戻ります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;編集側からヘルプバッファを経由して閉じたい場合&lt;/strong&gt;: ウィンドウ間を移動する &lt;strong&gt;&lt;code&gt;C-x o&lt;/code&gt;&lt;/strong&gt; （&lt;code&gt;other-window&lt;/code&gt;）でヘルプ側へカーソルを移してから &lt;code&gt;q&lt;/code&gt; を入力することでも同様に復帰できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="状態の識別と混乱を防ぐ要点"&gt;状態の識別と混乱を防ぐ要点&#10;&lt;/h2&gt;&lt;p&gt;操作に迷いが生じる原因は、キーシーケンスの破棄である &lt;strong&gt;入力の中断&lt;/strong&gt; と、画面レイアウトの復元である &lt;strong&gt;ウィンドウの破棄&lt;/strong&gt; という2つの異なる処理を混同しやすい点にあります。&lt;/p&gt;&#10;&lt;p&gt;画面が分割される前の入力待ちであれば &lt;strong&gt;&lt;code&gt;C-g&lt;/code&gt;&lt;/strong&gt; 、画面が分割された後であれば &lt;strong&gt;&lt;code&gt;q&lt;/code&gt;&lt;/strong&gt; または &lt;strong&gt;&lt;code&gt;C-x 1&lt;/code&gt;&lt;/strong&gt; というように、Emacsの画面状態に応じたキーを選択することが確実な復帰に繋がります。&lt;/p&gt;&#10;</description></item><item><title>東京が消し飛んでもシステムを復旧させるのか？──現場を凍りつかせる「BCPチェックシート」という名の茶番</title><link>https://ai.hack-le.com/%E6%9D%B1%E4%BA%AC%E3%81%8C%E6%B6%88%E3%81%97%E9%A3%9B%E3%82%93%E3%81%A7%E3%82%82%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%92%E5%BE%A9%E6%97%A7%E3%81%95%E3%81%9B%E3%82%8B%E3%81%AE%E3%81%8B%EF%BC%9F/</link><pubDate>Thu, 17 Sep 2026 23:32:10 +0900</pubDate><guid>https://ai.hack-le.com/%E6%9D%B1%E4%BA%AC%E3%81%8C%E6%B6%88%E3%81%97%E9%A3%9B%E3%82%93%E3%81%A7%E3%82%82%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%92%E5%BE%A9%E6%97%A7%E3%81%95%E3%81%9B%E3%82%8B%E3%81%AE%E3%81%8B%EF%BC%9F/</guid><description>&lt;p&gt;&lt;a class="link" href="https://gigazine.net/news/20260917-aws-middle-east-data-center-unable-to-restore/" target="_blank" rel="noopener"&#10; &gt;イランによるAmazonのデータセンターへの攻撃により顧客データが永久に失われる - GIGAZINE&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;中東にあるクラウド事業者のデータセンターが物理的な軍事攻撃を受け、単一アベイラビリティーゾーンに配置されていたデータが恒久的に失われたという報せは、インフラエンジニアや企業のリスク管理部門に冷水を浴びせました。どれほど論理的に抽象化されていようと、クラウドの実体は特定の緯度と経度に固定されたコンクリートとシリコンの塊であり、不可逆な物理破壊の前には無力であるという冷厳な事実です。&lt;/p&gt;&#10;&lt;p&gt;しかし、このニュースに触れたとき、私たちが真に直面させられるのは技術的アーキテクチャの敗北だけではありません。日本の多くの大企業で機械的に配られ、現場のエンジニアが半ば虚無感とともに記入させられている「事業継続計画（BCP）チェックシート」の欺瞞こそが、白日の下に晒されたと言えます。&lt;/p&gt;&#10;&lt;h2 id="基幹インフラだけが無傷というsf的ご都合主義"&gt;「基幹インフラだけが無傷」というSF的ご都合主義&#10;&lt;/h2&gt;&lt;p&gt;教科書的なBCPやクラウドの設計論では、東京リージョン（ap-northeast-1）が被災した際の解として「米国バージニア州（us-east-1）などへのマルチリージョン・フェイルオーバー」が平然と語られます。アーキテクチャ図の上では、太平洋を跨ぐ矢印を一本引くだけで対策が完了したかのように見えます。&lt;/p&gt;&#10;&lt;p&gt;しかし、現実の物理世界を少しでも想像すれば、この前提がギャグの領域にあることは明白です。東京が物理的に瓦解するほどの軍事攻撃や巨大災害が発生したとき、なぜ房総半島や茨城沿岸にある海底ケーブル陸揚局（CLS）や、都心のインターネットエクスチェンジ（IX）、超高圧変電所だけが奇跡的に無傷で稼働し続けているのでしょうか。&lt;/p&gt;&#10;&lt;p&gt;大動脈である太平洋横断ケーブル網や中継施設への給電が落ちれば、海外リージョンへのデータハイウェイそのものが瞬時に遮断されます。配管が根元から爆破されているのに、蛇口の先の水質を議論しているようなものです。海外拠点でデータが無事であろうと、それを国内の誰も参照できず、操作もできない状態であれば、そのシステムは宇宙空間を漂う無人の人工衛星と何ら変わりません。&lt;/p&gt;&#10;&lt;h2 id="この状況で仕事するわけないだろという正常な直感"&gt;「この状況で仕事するわけないだろ」という正常な直感&#10;&lt;/h2&gt;&lt;p&gt;さらに奇怪なのは、そうした極限状態においても「生身の担当者が平然と職務を遂行する」という前提がチェックシートの裏に忍ばされている点です。&lt;/p&gt;&#10;&lt;p&gt;東京が壊滅的な打撃を受け、明日また第2波の攻撃や激しい余震が来るかもしれないという状況下で、人間が真っ先に取るべき行動は一つしかありません。家族の安全を確保し、水と食料を抱えて、生存のために&lt;strong&gt;一刻も早く東京から脱出すること&lt;/strong&gt;です。&lt;/p&gt;&#10;&lt;p&gt;電気も水道も止まり、通信も途絶えた混乱の都市において、脱出の判断を数時間誤ることはそのまま死に直結します。そんな極限状態に置かれた生身の人間に対して、「担当サービスを他リージョンへ切り替えて持続性を担保できるか」と問うこと自体、破綻した状況認識と言うほかありません。&lt;/p&gt;&#10;&lt;p&gt;チェックシートを埋めながら多くのエンジニアが抱く「この状況で仕事するわけないだろ」という吐き捨てるような直感は、職責の放棄などではなく、生命を維持しようとする生物として最も健全で正確な現実認識です。&lt;/p&gt;&#10;&lt;h2 id="組織防衛のためのアリバイ工作と責任の所在"&gt;組織防衛のためのアリバイ工作と責任の所在&#10;&lt;/h2&gt;&lt;p&gt;では、なぜこのような絵空事のチェックシートが、大企業では全サービスの担当者に向けて一律に強制されるのでしょうか。理由は極めてシンプルで、それが現場の危機管理のためではなく「組織のアリバイ作り」として運用されているからです。&lt;/p&gt;&#10;&lt;p&gt;経営陣やリスク管理部門の目的は、実際に国家機能が麻痺したときにサービスを復旧させることではありません。株主総会、監査法人、取引先に対して「当社は全社的にリスクを評価し、統制を図っています」と報告するためのエビデンス、すなわち「記入済みシートの束」を揃えることが自己目的化しています。&lt;/p&gt;&#10;&lt;p&gt;そしてこの構造の最も残酷な点は、想定外の破滅が起きた際の泥を現場に被せられる余地を残していることです。「事前に貴方がこの時間で復旧できると書きましたよね」という手続きを踏ませることで、管理側は免責され、破綻の責任は「現場の見通しの甘さ」へと矮小化されます。&lt;/p&gt;&#10;&lt;h2 id="欺瞞を捨て本当の生存から逆算する"&gt;欺瞞を捨て、本当の「生存」から逆算する&#10;&lt;/h2&gt;&lt;p&gt;平時のビジネスやSaaSが提供する価値は、社会インフラと法秩序という巨大な土台が正常に維持されていて初めて成立する二次的な産物に過ぎません。&lt;/p&gt;&#10;&lt;p&gt;組織の体裁を保つための書類仕事に大人の対応として付き合うことは、サラリーマンとしての処世術かもしれません。しかし、心の奥底にある「世界が終わっているときに、会社のシステムを心配している場合ではない」という冷徹な感覚だけは手放してはなりません。&lt;/p&gt;&#10;&lt;p&gt;物理インフラが国家間の武力衝突や未曾有の大災害に巻き込まれたとき、真に問われるのはSaaSの可用性ではなく、私たち自身がいかに今日を生き延びるかという、剥き出しのサバイバルなのです。&lt;/p&gt;&#10;</description></item><item><title>セルフホストLANにIPv6は本当に必要か？タワマン建設の論理と、個人のDIYを取り戻す話</title><link>https://ai.hack-le.com/%E3%82%BB%E3%83%AB%E3%83%95%E3%83%9B%E3%82%B9%E3%83%88lan%E3%81%ABipv6%E3%81%AF%E6%9C%AC%E5%BD%93%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%8B%EF%BC%9F%E3%82%BF%E3%83%AF%E3%83%9E%E3%83%B3%E5%BB%BA%E8%A8%AD/</link><pubDate>Thu, 17 Sep 2026 14:27:24 +0900</pubDate><guid>https://ai.hack-le.com/%E3%82%BB%E3%83%AB%E3%83%95%E3%83%9B%E3%82%B9%E3%83%88lan%E3%81%ABipv6%E3%81%AF%E6%9C%AC%E5%BD%93%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%8B%EF%BC%9F%E3%82%BF%E3%83%AF%E3%83%9E%E3%83%B3%E5%BB%BA%E8%A8%AD/</guid><description>&lt;p&gt;自宅でサーバーを立てたり、さまざまなオープンソースのツールを動かしたりする「セルフホスト」を楽しむ人が増えています。ネットワーク界隈の情報を見ていると、「これからはIPv6の時代だ」という言説を頻繁に見かけます。&lt;/p&gt;&#10;&lt;p&gt;しかし、実際に自宅LANで手を動かしていると、ある疑問に突き当たります。「自分の家のネットワークでまで、本当にIPv6を使いこなす必要があるのだろうか？」ということです。結論から言えば、&lt;strong&gt;一般的なセルフホスト環境のLAN内においては、プライベートIPv4を主軸に据える運用のほうが圧倒的に合理的で扱いやすい&lt;/strong&gt;のが実情です。&lt;/p&gt;&#10;&lt;h2 id="タワマン建設の論理とガレージのdiy"&gt;タワマン建設の論理と、ガレージのDIY&#10;&lt;/h2&gt;&lt;p&gt;IPv6が強力に推される最大の理由は、世界規模で枯渇しつつあるIPv4アドレス空間の制約を打破することにあります。地球上のあらゆる機器に一意なIPアドレスを割り振るという壮大な目標のために、IPv6は設計されました。&lt;/p&gt;&#10;&lt;p&gt;大規模なデータセンターや通信キャリア、巨大クラウドプラットフォームの現場では、この圧倒的なスケーラビリティが不可欠です。彼らにとってのアドレス管理は、DNSによる自動名前解決やコードによる構成管理（IaC）を通じて高度に抽象化されており、運用者が手動でIPアドレスを打ち込む世界ではありません。例えるなら、彼らが作っているのは巨大なタワマンです。&lt;/p&gt;&#10;&lt;p&gt;一方、私たちが自宅で行っているセルフホストは、ガレージで行う木工DIYのようなものです。自分の手でOSを入れ、LANケーブルを繋ぎ、お気に入りのWebサービスを立ち上げる。そこでは、自分の目で見てすぐ把握できる3桁×4の数字（プライベートIPv4）のほうが、道具としての手触りが圧倒的に優れています。&lt;/p&gt;&#10;&lt;p&gt;ガレージでちょっとした棚を作りたいだけなのに、「将来の拡張性と耐震性のために、まずは大型クレーンの搬入経路を確保し、免震ゴムを基礎に打ち込みましょう」と言われているような違和感。これが、個人宅のLANにIPv6を過剰に持ち込もうとしたときに感じるストレスの正体です。&lt;/p&gt;&#10;&lt;h2 id="セルフホストの現場でipv6が引き起こす泥臭いトラブル"&gt;セルフホストの現場でIPv6が引き起こす泥臭いトラブル&#10;&lt;/h2&gt;&lt;p&gt;実際にAdGuard Home（AGH）などのローカルDNSや、Caddyのようなリバースプロキシを自宅で動かしてみると、IPv6の設計思想が個人の管理と真っ向から衝突することがよくわかります。&lt;/p&gt;&#10;&lt;p&gt;IPv6には「SLAAC（ステートレス自動設定）」や「プライバシー拡張」といった便利な機能が組み込まれています。しかし、端末が自身のアドレスを勝手に決め、プライバシー保護のために頻繁に一時アドレスを生成して使い捨てるという挙動は、静的にサービスを固定して管理したいセルフホスト環境では大きな障害になります。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;クライアントが特定できない&lt;/strong&gt;：AGHのダッシュボードを開いても、暗号のような16進数のアドレスが次々と並び、家の中のどのスマホやPCがクエリを投げているのか一目では判別できません。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;設定の追従が難しい&lt;/strong&gt;：Caddyなどのリバースプロキシにアップストリーム先のアドレスを記述する際、端末側のアドレスやISPから降ってくるプレフィックスが変わってしまうと、ルーティングが容易に壊れます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;トラブルシューティングの難航&lt;/strong&gt;：1つのネットワークインターフェースに複数のIPv6アドレスが付与されるため、通信が通らないときにどのアドレスで詰まっているのかを切り分ける手間が跳ね上がります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;対外的なインターネット通信については、ルーター側がMAP-EやDS-Liteといった技術、あるいは適切なNATやデュアルスタックによってIPv6の高速なバックボーンへ橋渡ししてくれます。つまり、&lt;strong&gt;LAN内の通信を無理にIPv6で統一しなくても、回線速度や帯域の恩恵はルーターの境界で十分に享受できる&lt;/strong&gt;のです。&lt;/p&gt;&#10;&lt;h2 id="コンピュータはキャリアアップの道具ではなく生活を便利にするおもちゃだ"&gt;コンピュータは「キャリアアップの道具」ではなく「生活を便利にするおもちゃ」だ&#10;&lt;/h2&gt;&lt;p&gt;最近の技術的な発信を見ていると、何事も「エンジニアとしてのスキルアップ」「実務に役立つポートフォリオ作り」という文脈で語られがちです。「自宅でサーバーを触ることもインフラの基礎勉強になる」という意見自体は間違いではありませんが、それが主目的になってしまうと、純粋な道具としての面白さが失われてしまいます。&lt;/p&gt;&#10;&lt;p&gt;私たちが自宅でサーバーをいじるのは、残業の続きをしたいからでも、資格試験の勉強をしたいからでもないはずです。&lt;/p&gt;&#10;&lt;p&gt;AdGuard Homeを立てるのは、家中の端末から鬱陶しい広告を消し去りたいからです。Caddyを使うのは、ブラウザの証明書エラーに邪魔されず、手元の管理画面へ快適にアクセスしたいからです。外部クラウドの仕様変更や利用料金に怯えることなく、自分のデータやサービスを自分のルールで動かす。その結果として「自分の生活が目に見えて快適になった」という実利があり、思い通りにパケットが流れたときの達成感が楽しいからこそ、手を動かしています。&lt;/p&gt;&#10;&lt;p&gt;実務に役立つかどうかや、最新のグローバル標準に準拠しているかどうかに過剰に縛られる必要はありません。目の前の箱をガチャガチャと動かし、自分の暮らしを自分の手でちょっと便利にする。その原点に立ち返るなら、扱いやすくて枯れ切ったIPv4をLAN内で使い倒すという選択は、妥協などではなく、極めて健全で合理的な現場の知恵と言えます。&lt;/p&gt;&#10;</description></item><item><title>自縄自縛の巨頭たち――生成AIの荒野で「魂」を見失ったAppleとMicrosoft</title><link>https://ai.hack-le.com/%E8%87%AA%E7%B8%84%E8%87%AA%E7%B8%9B%E3%81%AE%E5%B7%A8%E9%A0%AD%E3%81%9F%E3%81%A1%E2%80%95%E2%80%95%E7%94%9F%E6%88%90ai%E3%81%AE%E8%8D%92%E9%87%8E%E3%81%A7%E3%80%8C%E9%AD%82%E3%80%8D%E3%82%92%E8%A6%8B/</link><pubDate>Thu, 17 Sep 2026 13:21:57 +0900</pubDate><guid>https://ai.hack-le.com/%E8%87%AA%E7%B8%84%E8%87%AA%E7%B8%9B%E3%81%AE%E5%B7%A8%E9%A0%AD%E3%81%9F%E3%81%A1%E2%80%95%E2%80%95%E7%94%9F%E6%88%90ai%E3%81%AE%E8%8D%92%E9%87%8E%E3%81%A7%E3%80%8C%E9%AD%82%E3%80%8D%E3%82%92%E8%A6%8B/</guid><description>&lt;p&gt;パーソナルコンピュータの歴史を築き上げてきた二大巨頭、AppleとMicrosoftが、生成AIの急速な台頭という巨大な転換期を前に揃って深刻な機能不全を起こしています。&lt;/p&gt;&#10;&lt;p&gt;かつて世界中のギークや開発者を熱狂させ、確固たる信頼を勝ち得ていた両社は、今や株主へのアピールとプラットフォームの強権的な囲い込みに追われ、自らが築いた強みによって自らの首を絞めるという皮肉な現実に直面しています。&lt;/p&gt;&#10;&lt;h2 id="知性の自転車を去勢したappleの妥協"&gt;「知性の自転車」を去勢したAppleの妥協&#10;&lt;/h2&gt;&lt;p&gt;Appleのハードウェア、とりわけMac miniなどに搭載されるApple Siliconは、広大な帯域幅を持つユニファイドメモリアーキテクチャ（UMA）を備えています。これは意図した副産物とはいえ、ローカル環境で自律型AIエージェントや大規模言語モデルを常時稼働させるための母艦として、市井のハッカーや開発者から熱狂的な支持を集めました。&lt;/p&gt;&#10;&lt;p&gt;しかし、Apple自身が提示するAIのビジョンは、この現場の熱量とは正反対を向いています。自前のNeural Engineと「Apple Intelligence」が目指しているのは、サンドボックスで厳重に囲い込まれ、極限まで当たり障りのない要約や書き直しを行う「去勢された家電」に過ぎません。&lt;/p&gt;&#10;&lt;p&gt;スティーブ・ジョブズはかつてコンピュータを「人間の能力を何倍にも拡張する知性の自転車」と定義しました。乗り手が主導権を握り、自らの身体感覚を拡張する道具であるという哲学です。しかし現代の生成AIは、確率論的で予測不能なブラックボックスであり、ジョブズ的なコントロールフリークの美学とは根本から衝突します。&lt;/p&gt;&#10;&lt;p&gt;もし知性の自転車を進化させるためのパーツをAIに作らせるのだとすれば、それは本来のハッカー精神にかなうはずでした。しかし、Mac OS X Lion以降に進んだ「iOS化」によるガチガチのセキュリティ制限、公証制度、アクセシビリティ権限の壁が、自律エージェントの自由なOS操作を阻みます。&lt;/p&gt;&#10;&lt;p&gt;スティーブ・ウォズニアックがApple IIに込めた「中を開け、自由に回路を拡張させろ」というハッカーの魂を切り捨て、安全な箱庭の維持を最優先にした結果、Appleは自らが生み出した最高峰のハードウェアを真の意味で解放できずにいます。&lt;/p&gt;&#10;&lt;h2 id="互換性の執念を捨て広告枠へと成り下がったwindows"&gt;互換性の執念を捨て、広告枠へと成り下がったWindows&#10;&lt;/h2&gt;&lt;p&gt;一方でMicrosoftの自壊は、さらに泥臭い実務の現場を直撃しています。&lt;/p&gt;&#10;&lt;p&gt;かつてのスティーブ・バルマーが「Developers!」と叫び続けた時代、Windowsには異常なまでの執念がありました。OS側の挙動を意図的に曲げてまで過去の有名ゲームのバグを回避させた逸話に象徴されるように、「過去のソフトウェア資産を絶対に壊さない」という狂気的な後方互換性への誓いこそが、世界中の企業や開発者を繋ぎ止める絶対の信頼でした。&lt;/p&gt;&#10;&lt;p&gt;世界がWindowsを買い続ける真の理由は、25年前に作られたWin32アプリケーションを動かすためであり、四半世紀にわたって現場を支え続けるExcel資産を寸分違わず処理するためです。決してデスクトップを勝手にOneDriveへ巻き上げられるためでも、スタートメニューにBingの検索広告やトレンドニュースを表示させるためでもありません。&lt;/p&gt;&#10;&lt;p&gt;しかし現在のMicrosoftは、OS自身が自己主張を繰り返し、自社クラウドや有料サービスの押し売りを行うアドウェアのような存在へと変質しました。&lt;/p&gt;&#10;&lt;p&gt;そのツケは、AI時代におけるハードウェアコストの高騰と合流して決定的な喜劇を生み出しています。かつて軽量なネイティブコードで書かれていた標準の「天気」アプリは、開発コスト削減のためにEdge（Chromium）のラッパー技術であるWebView2へと置き換えられ、広告スクリプトの読み込みも相まって、ただ起動するだけで1GBを超えるメモリを貪り食うという異常事態を引き起こしました。&lt;/p&gt;&#10;&lt;p&gt;AIブームによってメモリやハードウェアが高騰し、世界中で稼働する8GBクラスのPCに配慮せざるを得ない状況に直面しながら、自社の作った天気予報ひとつ満足に低負荷で動かせない。かつてOSの足元を支えた熟練エンジニアの手触りは失われ、OSというインフラそのものが自重で崩れ始めています。&lt;/p&gt;&#10;&lt;h2 id="失われた原点と野生のai戦場"&gt;失われた原点と、野生のAI戦場&#10;&lt;/h2&gt;&lt;p&gt;今回のAI革命は、誰もいない更地を切り開くフロンティアではありません。すでに確立された日常という都市空間に、強力な最新兵器が突如として投下された市街戦です。&lt;/p&gt;&#10;&lt;p&gt;市井のゲリラや新興の開発企業は、その兵器を泥臭くハックし、自らの手足を拡張する道具として爆発的なスピードで実用化を進めています。その中で、かつて世界を制覇したはずの正規軍であるAppleとMicrosoftは、過去の成功体験から生まれた「囲い込みと収益化の縄目」に足を取られ、最も不恰好に立ち往生しています。&lt;/p&gt;&#10;&lt;p&gt;Appleに必要なのは、すべてを管理下に置こうとする傲慢さを手放し、ハードウェアの圧倒的なポテンシャルを野良の開発者に明け渡す「ウォズニアックの魂」を取り戻すことです。&lt;/p&gt;&#10;&lt;p&gt;Microsoftに必要なのは、自らを広告プラットフォームだと勘違いするのをやめ、無条件で開発者とユーザーの足元を静かに支える「透明な黒衣」へと立ち戻ることです。&lt;/p&gt;&#10;&lt;p&gt;自ら巻いた縄目を解き、道具としての誠実さを取り戻すことができるのか。それとも肥大化した家電と広告看板のまま、野生のテクノロジーの激流に呑まれていくのか。パーソナルコンピュータを定義した両雄は、かつてない分水嶺に立たされています。&lt;/p&gt;&#10;</description></item><item><title>サーバレスの夢の残骸</title><link>https://ai.hack-le.com/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%AC%E3%82%B9%E3%81%AE%E5%A4%A2%E3%81%AE%E6%AE%8B%E9%AA%B8/</link><pubDate>Sat, 12 Sep 2026 14:05:03 +0900</pubDate><guid>https://ai.hack-le.com/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%AC%E3%82%B9%E3%81%AE%E5%A4%A2%E3%81%AE%E6%AE%8B%E9%AA%B8/</guid><description>&lt;h2 id="aws文学と一次資料至上主義の病理"&gt;「AWS文学」と一次資料至上主義の病理&#10;&lt;/h2&gt;&lt;p&gt;かつて多くのエンジニアが、AWSの膨大な公式ドキュメントをお経のように熱心に読み解き、そこに書かれた仕様を忠実に実装することを美徳としていた時代がありました。難解で重層的な修飾節が連なり、例外規定と免責条項が張り巡らされたその独特な文体は、いつしか「AWS文学」と揶揄されるようになりました。この読みづらさは偶然の産物ではなく、コンウェイの法則に従って細分化された組織構造、サービスごとに異なる文脈、そして障害発生時の免責を徹底しようとする法律文書に近い執筆スタイルが重なり合った必然の結果です。&lt;/p&gt;&#10;&lt;p&gt;本来、技術者が真に求めているのは「目の前のシステムをどう安全に動かすか」という具体的な設計判断や勘所です。しかし、プラットフォーマーが公式文書として提示するのは「仕様の完全な網羅と免責」にすぎません。それにもかかわらず、業界には「一次資料こそが絶対の正義である」という盲目的な信仰が定着しました。一次資料が保証するのはあくまで現行実装に対する法的な正確さであり、読者が目的を達成するための実用性とは本質的に無関係です。難解なドキュメントと格闘したサンクコストを正当化し、二次情報を軽視して門番のように振る舞う文化は、エンジニアリングを手段から知的なマウンティングの道具へと変質させていきました。&lt;/p&gt;&#10;&lt;p&gt;現場を経験したエンジニアであれば誰しも、「ドキュメント上で保証されている仕様」と「本番環境の物理レイヤーで現実に起きる挙動」の間に横たわる深い溝を知っています。結果整合性の遅延、隠れたクォータ制限、ネットワーク断に伴う見かけ上のエラーなど、仕様書の外側にこそ現実の泥沼があります。何を読み、何を読まないかという情報選定の段階からエンジニアの責任は始まっています。公式の言説を無批判に崇める姿勢は、巨大プラットフォーマーのブランド力に自らの野生と批評精神を明け渡した結果にほかなりませんでした。&lt;/p&gt;&#10;&lt;h2 id="クラウドへの屈服とアーキテクチャの複雑性の爆発"&gt;クラウドへの屈服とアーキテクチャの複雑性の爆発&#10;&lt;/h2&gt;&lt;p&gt;なぜあの時代、これほど多くのエンジニアや組織が思考停止に陥り、プラットフォームに従属していったのでしょうか。その背景には、抗いがたい時代の構造的圧力が存在していました。かつてのオンプレミス環境における深夜のデータセンター作業、突然死するハードウェア、調達に数ヶ月を要する見積もりといった運用地獄からの解放は、あまりにも強烈なカタルシスをもたらしました。その恩恵の大きさゆえに、多少の歪みや理不尽には目を瞑るという暗黙の取引が成立してしまったのです。&lt;/p&gt;&#10;&lt;p&gt;さらに、資産を持たない身軽さを求める経営層からの強力なトップダウンや、急速に膨張する業界で未経験者を即戦力化するための「認定資格」を中心とした教育の標準化が、この流れを加速させました。その結果、エンジニアリングの本質である泥臭い問題解決能力よりも、プラットフォーム固有のお作法をどれだけ記憶しているかが重宝される歪んだ土壌が完成しました。&lt;/p&gt;&#10;&lt;p&gt;こうして熱狂の中で迎えられたクラウドでしたが、システムの進化は新たな袋小路へと突き当たります。S3、DynamoDB、Lambda、SQSといったサービス群は、インフラの存在を忘れさせる圧倒的な未来を確かに予感させました。しかし、それらを組み合わせて巨大な業務システムを構築しようとした瞬間、&lt;strong&gt;アーキテクチャの複雑性の爆発&lt;/strong&gt;という過酷な代償を支払うことになりました。&lt;/p&gt;&#10;&lt;p&gt;かつてモノリスの内部でメモリ上の関数呼び出しとして完結していた処理が、細切れのマイクロサービスやイベント駆動へと分解された結果、単なるデータの受け渡しがすべてネットワーク越しの分散トランザクションへと化しました。重複配信への対策、メッセージの順序制御、デッドレターキューの監視、そして数千行に及ぶ設定ファイル（IaC）の保守など、コードの行数を減らした代わりにインフラの接続点と失敗パターンが指数関数的に増大していったのです。&lt;/p&gt;&#10;&lt;h2 id="コンテナオーケストレーションという名の欺瞞"&gt;コンテナオーケストレーションという名の欺瞞&#10;&lt;/h2&gt;&lt;p&gt;分散システムの複雑性に疲弊した業界が次に逃げ込んだのが、ECSやKubernetesをはじめとするコンテナオーケストレーションでした。しかし、それは解決策どころか、さらなる高額な固定費と運用の怪物を飼い慣らす選択にすぎませんでした。&lt;/p&gt;&#10;&lt;p&gt;コンテナオーケストレーションは、本質的に&lt;strong&gt;IaaS（仮想インフラ）のレイヤーにとどまるリソース占有型のモデル&lt;/strong&gt;です。どれだけ軽量なコンテナを動かそうと、背後には24時間365日稼働し続ける仮想マシンやプロビジョニングされたリソースが存在します。そこにコントロールプレーンの維持費、高額なデータ転送料、監視エージェントのオーバーヘッド、そして安全マージンとして死蔵される大量の空きリソースが積み重なります。結果として、何も処理していなくても毎月莫大なプラットフォーム税が徴収される構造から抜け出せなくなりました。&lt;/p&gt;&#10;&lt;p&gt;現代の物理ハードウェアは目覚ましい進化を遂げています。コンテナ基盤に投じられる年間数百万円から数千万円規模のコストがあれば、最新のワークステーションやサーバー、堅牢なネットワーク機器を一式揃え、さらには物理的なオフィススペースの賃料を払ってもお釣りが来るという計算は、決して荒唐無稽な暴論ではありません。「可用性とスケーラビリティ」という美名のもとに仮想化レイヤーの上で自作PCごっこを繰り返す経済的な不条理に、多くの現場が直面しています。&lt;/p&gt;&#10;&lt;h2 id="果たせぬ夢だったサーバレスと物理バイナリへの誇り"&gt;果たせぬ夢だったサーバレスと、物理バイナリへの誇り&#10;&lt;/h2&gt;&lt;p&gt;いま振り返るべきは、私たちがかつて信じた&lt;strong&gt;真のサーバレスアーキテクチャの思想&lt;/strong&gt;とは何であったかという問いです。だからこそ、コンテナを裏で自動起動するだけの仕組みを「サーバレス」と呼ぶ昨今の風潮には、強い違和感を覚えざるを得ません。それは、かつての美しい思想に対するマーケティング的な簒奪でした。&lt;/p&gt;&#10;&lt;p&gt;本来のサーバレスが提示した革命とは、以下のような計算モデルの根本的な転換でした。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;常駐（Daemon）からの解放&lt;/strong&gt;リクエストを待ち受けるためにリソースを占有し続ける旧来のあり方を否定し、事象（Event）が発生したその刹那だけ実体化し、計算を終えたら跡形もなく虚空へ消え去るという儚くも無駄のないモデル。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;因果関係の記述への純化&lt;/strong&gt;ハードウェアのキャパシティに頭を悩ませるのではなく、世界で起きる変化に対して純粋関数をマッピングしていくという、プログラミングの原初的な快感への回帰。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ゼロの誠実さ&lt;/strong&gt;動いていない時間には1円のコストも発生させないという、真の従量課金がもたらす透明で合理的な経済性。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;DynamoDBやLambdaは、強烈なベンダーロックインと引き換えにこの思想を極限まで具現化した稀有な道具であり、その純粋な割り切りとコストパフォーマンスにおいて、今なお独自の輝きを放っています。しかし、その純粋な思想は、業界全体の複雑化と巨大なプラットフォームビジネスの波に呑み込まれ、果たせぬ夢として終わりました。&lt;/p&gt;&#10;</description></item><item><title>Mac上のOllamaで動かすGemma 4環境構築と外部Linux（Open WebUI）からの接続ガイド</title><link>https://ai.hack-le.com/mac%E4%B8%8A%E3%81%AEollama%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99gemma-4%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%A8%E5%A4%96%E9%83%A8linux%EF%BC%88open-webui%EF%BC%89%E3%81%8B%E3%82%89%E3%81%AE/</link><pubDate>Sat, 12 Sep 2026 12:09:19 +0900</pubDate><guid>https://ai.hack-le.com/mac%E4%B8%8A%E3%81%AEollama%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99gemma-4%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%A8%E5%A4%96%E9%83%A8linux%EF%BC%88open-webui%EF%BC%89%E3%81%8B%E3%82%89%E3%81%AE/</guid><description>&lt;p&gt;ローカル環境で手軽に大規模言語モデルを稼働させられる基盤として定評のある&lt;strong&gt;Ollama&lt;/strong&gt;は、Apple Silicon（Mシリーズ）のユニファイドメモリと広い帯域幅を活用することで、優れた推論パフォーマンスを発揮します。本稿では、Mac環境における&lt;strong&gt;Gemma 4&lt;/strong&gt;（e4bおよび12b）の導入手順からハードウェア別の性能目安、さらに別のLinuxマシンで起動している&lt;strong&gt;Open WebUI&lt;/strong&gt;と連携する際に直面しやすいネットワークの疎通課題とその解決策について解説します。&lt;/p&gt;&#10;&lt;h2 id="gemma-4モデルの導入と基本的な管理"&gt;Gemma 4モデルの導入と基本的な管理&#10;&lt;/h2&gt;&lt;p&gt;公式サイトからダウンロードができます。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://ollama.com/download/mac" target="_blank" rel="noopener"&#10; &gt;Download Ollama on macOS&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://ollama.com/install.sh &lt;span class="p"&gt;|&lt;/span&gt; sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;インストール完了後、モデルのダウンロードを実行します。軽量・高効率な&lt;strong&gt;gemma4:e4b&lt;/strong&gt;と、論理推論やコーディング支援にバランスの取れた&lt;strong&gt;gemma4:12b&lt;/strong&gt;を用途に合わせて取得します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 軽量エッジ向けモデルの取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama pull gemma4:e4b&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 標準バランス向けモデルの取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama pull gemma4:12b&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ターミナル上で直接対話を行う場合は &lt;code&gt;ollama run &amp;lt;モデル名&amp;gt;&lt;/code&gt; を使用します。また、不要となったモデルを削除してストレージを解放する場合は、リストで正確な識別子を確認した上で削除コマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# インストール済みモデルの確認&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 指定モデルの削除&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama rm gemma4:e4b&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="m2-pro環境におけるパフォーマンスの目安"&gt;M2 Pro環境におけるパフォーマンスの目安&#10;&lt;/h2&gt;&lt;p&gt;Apple Siliconを搭載したMacはGPUとCPUが同一のメモリ領域を共有するため、大規模モデルの展開に適しています。一例として、メモリ帯域幅200GB/sを備えるM2 Pro（RAM 16GB構成）における各モデルの挙動は以下の通りです。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;gemma4:e4b&lt;/strong&gt;: 4bit量子化時のサイズは約2.5GB〜3.5GB程度に収まり、生成速度は&lt;strong&gt;50〜70 tokens/sec&lt;/strong&gt;に達します。瞬時にテキストが生成されるため、ツールの呼び出し（Function Calling）や即時応答性が求められる自動化タスクに最適です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;gemma4:12b&lt;/strong&gt;: 4bit量子化時のサイズは約7.5GB〜8.5GB、生成速度は&lt;strong&gt;22〜30 tokens/sec&lt;/strong&gt;程度を維持します。日本語の文章作成や推論プロセスを挟む処理でもストレスなく動作します。ただし、OSの基礎消費と合わせるとメモリ使用量が10GB前後に達するため、長大なコンテキストを扱う際はバックグラウンドアプリのメモリ競合に留意する必要があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="外部linuxマシンopen-webuiからmac-miniのollamaへ接続する"&gt;外部Linuxマシン（Open WebUI）からMac miniのOllamaへ接続する&#10;&lt;/h2&gt;&lt;p&gt;実用的な構成として、推論処理はGPUパワーとユニファイドメモリを持つMac miniに任せ、WebインターフェースであるOpen WebUIは常時稼働している別筐体のLinuxサーバーでホストする分散配置があります。&lt;/p&gt;&#10;&lt;p&gt;この構成において、Macのローカル内では &lt;code&gt;curl http://localhost:11434&lt;/code&gt; が成功するにもかかわらず、Linux側のOpen WebUIから接続できない事象が頻発します。この主因は、Ollamaの待ち受けIP制限とCORS（Cross-Origin Resource Sharing）設定にあります。&lt;/p&gt;&#10;&lt;p&gt;Ollamaは初期状態において、安全上の理由からループバックアドレス（&lt;code&gt;127.0.0.1&lt;/code&gt;）からの接続のみを待ち受けるよう設計されています。そのため、別マシンからのリクエストを受け付けるには、すべてのネットワークインターフェース（&lt;code&gt;0.0.0.0&lt;/code&gt;）を開放し、さらにオリジン検証を許可する環境変数をMac側へ設定する必要があります。&lt;/p&gt;&#10;&lt;p&gt;MacのGUIアプリ版Ollamaを利用している場合、一度メニューバーからアプリを終了した上で、ターミナルで以下のコマンドを実行してシステム環境変数を登録します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl setenv OLLAMA_HOST &lt;span class="s2"&gt;&amp;#34;0.0.0.0:11434&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl setenv OLLAMA_ORIGINS &lt;span class="s2"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;設定後にOllamaを再起動し、Mac側のターミナルでリッスン状態を確認します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsof -i :11434&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出力結果の接続先が &lt;code&gt;*:11434&lt;/code&gt; または &lt;code&gt;0.0.0.0:11434&lt;/code&gt; となっていれば外部接続の受付準備は完了です。併せて、macOSの「システム設定」&amp;gt;「ネットワーク」&amp;gt;「ファイアウォール」において、Ollama着信がブロックされていないか確認してください。&lt;/p&gt;&#10;&lt;p&gt;最後に、Linuxマシン側のターミナルからMacのローカルIP宛に通信疎通をテストします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://&amp;lt;MacのIPアドレス&amp;gt;:11434&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Ollama is running&lt;/code&gt; というレスポンスが返ればネットワーク経路が開通しています。あとはLinux上のOpen WebUIの設定画面（管理者パネル &amp;gt; 接続）にて、OllamaのURLを &lt;code&gt;http://&amp;lt;MacのIPアドレス&amp;gt;:11434&lt;/code&gt; に指定することで、Mac上のリソースを用いた快適なGUIチャット環境が実現します。&lt;/p&gt;&#10;</description></item><item><title>CaddyのファイルサーバーにBasic認証を設定する方法とドメイン追加時のreload挙動</title><link>https://ai.hack-le.com/caddy%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%ABbasic%E8%AA%8D%E8%A8%BC%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%A8%E3%83%89/</link><pubDate>Fri, 04 Sep 2026 15:49:56 +0900</pubDate><guid>https://ai.hack-le.com/caddy%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%ABbasic%E8%AA%8D%E8%A8%BC%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%A8%E3%83%89/</guid><description>&lt;p&gt;軽量でHTTPSの自動設定が強力なWebサーバー「Caddy」において、ファイルサーバー機能にBasic認証を付加する手順と、ドメイン追加時にサービス再起動が必要かどうかについてのまとめです。&lt;/p&gt;&#10;&lt;h2 id="basic認証の設定手順"&gt;Basic認証の設定手順&#10;&lt;/h2&gt;&lt;p&gt;Caddyで静的ファイルを配信する &lt;code&gt;file_server&lt;/code&gt; ディレクティブに対してBasic認証を設定する場合、平文のパスワードをそのままCaddyfileに記述することはできません。事前にパスワードのハッシュ値を生成し、それを設定ファイルに組み込む必要があります。&lt;/p&gt;&#10;&lt;p&gt;まず、サーバーのターミナル上で &lt;code&gt;caddy hash-password&lt;/code&gt; コマンドを実行します。対話形式でパスワードの入力を求められるため、使用したいパスワードを入力すると、bcryptアルゴリズムによって暗号化されたハッシュ文字列が出力されます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;caddy hash-password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 入力プロンプトにパスワードを入力すると、ハッシュ値が出力されます&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 出力例: $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR78lmQ827KnFsEK&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ハッシュ文字列が得られたら、Caddyfileのサイト定義内に &lt;code&gt;basicauth&lt;/code&gt; ディレクティブを追記します。サイト全体を保護する場合は以下のようにルートに配置します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; root * /var/www/html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Basic認証の設定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; basicauth &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ユーザー名 ハッシュ化されたパスワード&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; alice &lt;span class="nv"&gt;$2&lt;/span&gt;a&lt;span class="nv"&gt;$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT&lt;/span&gt;/5qqR78lmQ827KnFsEK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; file_server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;特定のディレクトリ（例: &lt;code&gt;/admin/&lt;/code&gt; 以下）のみを認証の対象としたい場合は、ディレクティブの直後にパスの指定をマッチャーとして付与することで適用範囲を限定できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; root * /var/www/html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# /admin 以下のパスのみ認証を要求&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; basicauth /admin/* &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; bob &lt;span class="nv"&gt;$2&lt;/span&gt;a&lt;span class="nv"&gt;$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT&lt;/span&gt;/5qqR78lmQ827KnFsEK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; file_server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ドメイン追加時の証明書発行とreloadの挙動"&gt;ドメイン追加時の証明書発行とreloadの挙動&#10;&lt;/h2&gt;&lt;p&gt;Caddyfileに新しいドメインを追加した際、Webサーバーのプロセスを &lt;code&gt;restart&lt;/code&gt; させる必要はありません。Caddyは &lt;strong&gt;reloadコマンドのみで証明書の発行まで完結&lt;/strong&gt; します。サービスを停止して再起動をかける必要はありません。&lt;/p&gt;&#10;&lt;p&gt;設定変更後は、サーバー上で &lt;code&gt;caddy reload&lt;/code&gt; または &lt;code&gt;systemctl reload caddy&lt;/code&gt; を実行します。Caddyはゼロダウンタイムで新しい設定を読み込み、構成に追加された新しいドメインを検知すると、即座にバックグラウンドでACME（Let&amp;rsquo;s EncryptやZeroSSLなど）を通じたSSL/TLS証明書の自動取得と適用を開始します。&lt;/p&gt;&#10;&lt;p&gt;ただし、正常に証明書が発行されるためには、前提条件として以下の2点が整っている必要があります。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;追加したドメインのDNSレコード（A/AAAA）が正しくサーバーのIPアドレスを向いていること&lt;/li&gt;&#10;&lt;li&gt;HTTP-01チャレンジなどの検証を通すため、外部から80番および443番ポートへの通信が疎通可能な状態であること&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;これらが満たされていれば、リロードを実行するだけで数秒から十数秒のうちにHTTPS通信が確立されます。&lt;/p&gt;&#10;</description></item><item><title>rsyncで「IO error encountered — skipping file deletion」が発生した原因と対処法</title><link>https://ai.hack-le.com/rsync%E3%81%A7%E3%80%8Cio-error-encountered-skipping-file-deletion%E3%80%8D%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%97%E3%81%9F%E5%8E%9F%E5%9B%A0%E3%81%A8%E5%AF%BE%E5%87%A6%E6%B3%95/</link><pubDate>Sun, 30 Aug 2026 12:37:13 +0900</pubDate><guid>https://ai.hack-le.com/rsync%E3%81%A7%E3%80%8Cio-error-encountered-skipping-file-deletion%E3%80%8D%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%97%E3%81%9F%E5%8E%9F%E5%9B%A0%E3%81%A8%E5%AF%BE%E5%87%A6%E6%B3%95/</guid><description>&lt;p&gt;rsyncを利用して定期的なローカルバックアップスクリプトを運用している際、転送処理中にエラーが発生して一部のファイル同期および削除処理がスキップされるトラブルに遭遇しました。今回はその原因の特定と、安全にスクリプトを修正して正常終了させるまでの手順をまとめます。&lt;/p&gt;&#10;&lt;h2 id="エラーの発生状況と原因"&gt;エラーの発生状況と原因&#10;&lt;/h2&gt;&lt;p&gt;バックアップスクリプトを実行したところ、転送の途中で以下のようなメッセージが出力されました。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;IO error encountered -- skipping file deletion&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync: &lt;span class="o"&gt;[&lt;/span&gt;sender&lt;span class="o"&gt;]&lt;/span&gt; opendir &lt;span class="s2"&gt;&amp;#34;/path/to/app1/data/db&amp;#34;&lt;/span&gt; failed: Permission denied &lt;span class="o"&gt;(&lt;/span&gt;13&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync: &lt;span class="o"&gt;[&lt;/span&gt;sender&lt;span class="o"&gt;]&lt;/span&gt; opendir &lt;span class="s2"&gt;&amp;#34;/path/to/app2/db-data&amp;#34;&lt;/span&gt; failed: Permission denied &lt;span class="o"&gt;(&lt;/span&gt;13&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync error: some files/attrs were not transferred &lt;span class="o"&gt;(&lt;/span&gt;see previous errors&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;code 23&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この現象には2つの連動した原因があります。&lt;/p&gt;&#10;&lt;p&gt;直接的な原因は、コンテナ等で稼働しているアプリケーション（データベースなど）のデータディレクトリに対して、一般ユーザー権限で実行していたrsyncがアクセスできず、&lt;strong&gt;Permission denied&lt;/strong&gt; となったことです。コンテナ内のプロセスが専用のUIDでディレクトリを作成しているため、一般ユーザーの読み取り権限が制限されていました。&lt;/p&gt;&#10;&lt;p&gt;間接的なエラーである &lt;code&gt;IO error encountered -- skipping file deletion&lt;/code&gt; は、rsyncが備えている安全機能によるものです。同期元でアクセスエラーや読み込み不可のファイルが発生した場合、rsyncはファイルが削除されたのか、単に読み込めないだけなのかを判別できません。そのため、同期先のファイルを誤って消去してしまわないよう、&lt;code&gt;--delete&lt;/code&gt; オプションによる削除処理を自動的に中断します。&lt;/p&gt;&#10;&lt;h2 id="対処法dbデータディレクトリの除外"&gt;対処法：DBデータディレクトリの除外&#10;&lt;/h2&gt;&lt;p&gt;稼働中のデータベースが持つ生データディレクトリをそのままファイル単位でrsync同期することは、データの整合性が崩れるリスクが高いため推奨されません。データベースのバックアップはダンプファイルを別途出力してそれを同期するのが安全です。&lt;/p&gt;&#10;&lt;p&gt;そのため、今回は読み取り権限のないデータベース関連のディレクトリを &lt;code&gt;--exclude&lt;/code&gt; オプションで明示的に除外する方針をとりました。&lt;/p&gt;&#10;&lt;p&gt;修正前のスクリプトでは、ドライブ直下のシステム用ディレクトリである &lt;code&gt;lost+found&lt;/code&gt; のみを除外していましたが、コンテナのデータディレクトリも除外対象へ追加しました。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync -avh --delete --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;lost+found&amp;#34;&lt;/span&gt; /path/to/source_disk1/ /path/to/backup_disk/disk1/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync -avh --delete --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;lost+found&amp;#34;&lt;/span&gt; /path/to/source_disk2/ /path/to/backup_disk/disk2/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync -avh --delete --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;lost+found&amp;#34;&lt;/span&gt; /path/to/user_data/ /path/to/backup_disk/share/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rsync -avh --delete &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;lost+found&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;app1/data/db&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;app2/db-data&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /path/to/applications/ /path/to/backup_disk/applications/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除外パスの指定は、同期元（&lt;code&gt;/path/to/applications/&lt;/code&gt;）からの相対パスで記述します。&lt;/p&gt;&#10;&lt;h2 id="修正後の動作確認"&gt;修正後の動作確認&#10;&lt;/h2&gt;&lt;p&gt;スクリプト修正後に再度実行したところ、アクセス権限エラーや削除スキップの警告は出力されなくなりました。&lt;/p&gt;&#10;&lt;p&gt;実行直後に &lt;code&gt;echo $?&lt;/code&gt; で終了ステータスを確認し、正常終了を示す &lt;strong&gt;0&lt;/strong&gt; が返ってくることを確認して作業完了としました。&lt;/p&gt;&#10;&lt;p&gt;権限エラーを無理やり無視する &lt;code&gt;--ignore-errors&lt;/code&gt; などのオプションに頼るのではなく、不要なディレクトリや整合性の担保できないデータディレクトリを適切に除外することが、堅牢なバックアップ運用につながります。&lt;/p&gt;&#10;</description></item><item><title>下品な無差別サーバ攻撃の不快感</title><link>https://ai.hack-le.com/%E4%B8%8B%E5%93%81%E3%81%AA%E7%84%A1%E5%B7%AE%E5%88%A5%E3%82%B5%E3%83%BC%E3%83%90%E6%94%BB%E6%92%83%E3%81%AE%E4%B8%8D%E5%BF%AB%E6%84%9F/</link><pubDate>Thu, 27 Aug 2026 23:33:57 +0900</pubDate><guid>https://ai.hack-le.com/%E4%B8%8B%E5%93%81%E3%81%AA%E7%84%A1%E5%B7%AE%E5%88%A5%E3%82%B5%E3%83%BC%E3%83%90%E6%94%BB%E6%92%83%E3%81%AE%E4%B8%8D%E5%BF%AB%E6%84%9F/</guid><description>&lt;p&gt;Webサイトを運用していると、海外の特定地域から意味をなさない無差別なアクセスや脆弱性スキャンが大量に押し寄せてくることがあります。実害としてはCPU使用率がわずかに上昇する程度で、システムが破綻する危険性は皆無であっても、管理者の精神やログ領域を無意味に汚染される不快感は拭えません。&lt;/p&gt;&#10;&lt;h2 id="無差別スキャンの実態と下品な攻撃がもたらす徒労感"&gt;無差別スキャンの実態と「下品な攻撃」がもたらす徒労感&#10;&lt;/h2&gt;&lt;p&gt;サイトの言語設定や稼働環境を一切無視して、存在しないWordPressのログインパス（&lt;code&gt;wp-login.php&lt;/code&gt;）や特定プラグインの脆弱性URLを機械的に乱打してくる行為は、高度なサイバー攻撃などではなく、単なる全IPアドレスへの絨毯爆撃です。感染したボットネットやスクリプトキディが、使い捨ての環境から無差別にツールを垂れ流しているに過ぎません。&lt;/p&gt;&#10;&lt;p&gt;かつてのハッカー文化や義賊的な存在に見られたような、一定の技術的哲学や対象への選定眼、抑制といったものはここには一切存在しません。成功確率が0%であるにもかかわらずリクエストを垂れ流す行為は、公共のインターネット空間に生ゴミを不法投棄しているのと同義です。&lt;/p&gt;&#10;&lt;p&gt;このような行為は、夜中に窓ガラスへ狂ったように体当たりを繰り返す害虫の羽音に似ています。室内へ侵入される危険性は皆無であるにもかかわらず、激突音を聞かされ、窓ガラスに汚れを残されることに対する純粋な生理的嫌悪感と徒労感だけが残ります。&lt;/p&gt;&#10;&lt;h2 id="結論としての防御方針"&gt;結論としての防御方針&#10;&lt;/h2&gt;&lt;p&gt;こうした低レベルなノイズに対して、オリジンサーバー側のリソースや管理者の意識を割くこと自体が無駄と言えます。CloudflareのようなCDN/WAFのエッジ側で機械的に&lt;code&gt;Block&lt;/code&gt;または&lt;code&gt;Managed Challenge&lt;/code&gt;を適用し、オリジンサーバーに一切到達させない構成を敷くことが、精神衛生上および運用管理上において最も費用対効果の高い対処法となります。&lt;/p&gt;&#10;</description></item><item><title>「サーバ」という言葉には3つの顔がある――初心者が最初につまずく理由と整理法</title><link>https://ai.hack-le.com/%E3%80%8C%E3%82%B5%E3%83%BC%E3%83%90%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E8%A8%80%E8%91%89%E3%81%AB%E3%81%AF3%E3%81%A4%E3%81%AE%E9%A1%94%E3%81%8C%E3%81%82%E3%82%8B%E2%80%95%E2%80%95%E5%88%9D%E5%BF%83/</link><pubDate>Thu, 27 Aug 2026 10:52:47 +0900</pubDate><guid>https://ai.hack-le.com/%E3%80%8C%E3%82%B5%E3%83%BC%E3%83%90%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E8%A8%80%E8%91%89%E3%81%AB%E3%81%AF3%E3%81%A4%E3%81%AE%E9%A1%94%E3%81%8C%E3%81%82%E3%82%8B%E2%80%95%E2%80%95%E5%88%9D%E5%BF%83/</guid><description>&lt;p&gt;ITの学習や業務の中で、私たちはごく自然に「サーバ」という言葉を使っています。しかし、一口にサーバと言っても、話す人や文脈によって指している対象がまったく異なることがあります。その違いを大別すると、&lt;strong&gt;物理的なハードウェア&lt;/strong&gt;、&lt;strong&gt;ソフトウェア&lt;/strong&gt;、そして&lt;strong&gt;役割を表す概念&lt;/strong&gt;の3つに分けられます。&lt;/p&gt;&#10;&lt;p&gt;このレイヤーのズレを意識しないまま会話を進めてしまうと、特に初学者の学習において大きな混乱の原因となります。本記事では、この3つの違いを論理的に整理し、なぜ初心者がつまずきやすいのかを備忘録としてまとめます。&lt;/p&gt;&#10;&lt;h2 id="3つのレイヤーで理解するサーバの正体"&gt;3つのレイヤーで理解する「サーバ」の正体&#10;&lt;/h2&gt;&lt;p&gt;サーバ（Server）という英単語の語源は、提供する・給仕するという意味を持つ &lt;code&gt;serve&lt;/code&gt; に由来します。レストランにおける「給仕係（店員）」と「客（クライアント）」の関係をイメージすると、3つの違いが明確になります。&lt;/p&gt;&#10;&lt;p&gt;1つ目は、&lt;strong&gt;概念・役割としてのサーバ&lt;/strong&gt;です。これはクライアント・サーバモデルと呼ばれるアーキテクチャや関係性そのものを指します。要求（リクエスト）を出す側をクライアント、その要求を受け取ってサービスやデータを返す（レスポンス）側をサーバと呼びます。ここには物理的な機械や特定のプログラムという実体の制約はなく、あくまで「要求に応じる役割」という抽象的な関係性を意味しています。&lt;/p&gt;&#10;&lt;p&gt;2つ目は、&lt;strong&gt;ソフトウェアとしてのサーバ&lt;/strong&gt;です。これはクライアントからの要求を処理して応答を返す具体的な&lt;strong&gt;プログラム&lt;/strong&gt;を指します。たとえば、Webページを配信する &lt;code&gt;Apache&lt;/code&gt; や &lt;code&gt;Nginx&lt;/code&gt;、データベースを管理する &lt;code&gt;MySQL&lt;/code&gt; や &lt;code&gt;PostgreSQL&lt;/code&gt; などがこれに該当します。手元のノートパソコンであっても、これらのソフトウェアをインストールして起動すれば、そのプログラムは立派なWebサーバやデータベースサーバとして機能します。&lt;/p&gt;&#10;&lt;p&gt;3つ目は、&lt;strong&gt;ハードウェアとしてのサーバ&lt;/strong&gt;です。これはサーバソフトウェアを安定して24時間365日動かし続けるために設計された&lt;strong&gt;物理的なコンピュータ機械&lt;/strong&gt;を指します。データセンターのラックに収められているような、高い耐障害性や連続稼働用の冷却性能を備えた専用マシンです。&lt;/p&gt;&#10;&lt;p&gt;これらを整理すると、「1台の物理コンピュータ（ハードウェア）の中で、複数のサーバプログラム（ソフトウェア）が稼働し、それぞれが利用者の要求に応えてデータを提供する（概念・役割）」という多重構造になっていることがわかります。&lt;/p&gt;&#10;&lt;h2 id="なぜ初心者はサーバという言葉でつまずくのか"&gt;なぜ初心者は「サーバ」という言葉でつまずくのか&#10;&lt;/h2&gt;&lt;p&gt;この3つの意味が日常会話で無意識に使い分けられていることこそが、初心者が学習初期に感じる混乱の根本的な原因です。具体的には、次のような場面で思考のフリーズが発生します。&lt;/p&gt;&#10;&lt;p&gt;まず、 &lt;strong&gt;「自分のパソコンがサーバになる」という感覚が掴めない&lt;/strong&gt;という問題があります。「サーバ＝データセンターにある巨大で特別な黒い箱」という先入観を持っていると、Web開発の入門時に「ローカル環境にWebサーバを立ち上げる」と指示された際、なぜ普通のノートPCが突然サーバになるのか理解できなくなります。自分のPC上で &lt;code&gt;localhost&lt;/code&gt; や &lt;code&gt;127.0.0.1&lt;/code&gt; に対してリクエストを送る行為は、同じマシン内でクライアント（ブラウザ）とサーバ（Webサーバソフト）が同時に動いている状態ですが、ハードウェアとソフトウェアを混同しているとこの構造が見えてきません。&lt;/p&gt;&#10;&lt;p&gt;次に、 &lt;strong&gt;「サーバが落ちた」というトラブルの解像度が低くなる&lt;/strong&gt;点です。障害が発生した際、物理マシンの電源やネットワークが切断されたのか、&lt;code&gt;Nginx&lt;/code&gt; などのプロセスが停止したのか、それともプログラム内部のバグで例外が発生したのかによって対処法は全く異なります。しかし、すべてを一括りに「サーバの問題」と捉えてしまうと、何が壊れているのかを正しく切り分けられなくなります。&lt;/p&gt;&#10;&lt;p&gt;さらに現代では、クラウドサービスや仮想化技術の普及により、物理と論理の境界がより曖昧になっています。AWSなどのクラウド上で仮想マシンを作成することを日常的に「サーバを立てる」と呼びますが、これはソフトウェアによって仮想的に作られたコンピュータであり、物理的な実体と1対1で結びついているわけではありません。&lt;/p&gt;&#10;&lt;h2 id="文脈のズレを意識して解像度を上げる"&gt;文脈のズレを意識して解像度を上げる&#10;&lt;/h2&gt;&lt;p&gt;私たちが普段何気なく交わしている会話を振り返ると、主語のレイヤーが頻繁に入れ替わっていることに気づきます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;サーバを契約する・購入する&lt;/strong&gt;（ハードウェアやインフラ設備の文脈）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;サーバをインストールする・起動する&lt;/strong&gt;（ソフトウェアやプロセスの文脈）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;サーバにリクエストを送信する&lt;/strong&gt;（概念やアーキテクチャの文脈）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;相手にサーバの仕組みを説明するときや、自身が技術的なトラブルシューティングを行うときは、いまどのレイヤーの話をしているのかを意識することが大切です。ハードウェア、ソフトウェア、そして概念という3つの視点を持つだけで、ITシステム全体の構造を格段にクリアに見通せるようになります。&lt;/p&gt;&#10;</description></item><item><title>なぜPCのアプリストアは失敗し、Windowsは自ら価値を損ね続けるのか――Win32の泥臭さと王者の慢心</title><link>https://ai.hack-le.com/%E3%81%AA%E3%81%9Cpc%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B9%E3%83%88%E3%82%A2%E3%81%AF%E5%A4%B1%E6%95%97%E3%81%97%E3%80%81windows%E3%81%AF%E8%87%AA%E3%82%89%E4%BE%A1%E5%80%A4%E3%82%92%E6%90%8D/</link><pubDate>Wed, 26 Aug 2026 10:44:11 +0900</pubDate><guid>https://ai.hack-le.com/%E3%81%AA%E3%81%9Cpc%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B9%E3%83%88%E3%82%A2%E3%81%AF%E5%A4%B1%E6%95%97%E3%81%97%E3%80%81windows%E3%81%AF%E8%87%AA%E3%82%89%E4%BE%A1%E5%80%A4%E3%82%92%E6%90%8D/</guid><description>&lt;h2 id="白紙のスマホと歴史が完成していたpcの構造的断絶"&gt;白紙のスマホと、歴史が完成していたPCの構造的断絶&#10;&lt;/h2&gt;&lt;p&gt;スマートフォンにおいてアプリストアモデルが絶対的な成功を収めた一方で、PCやMacにおけるストア構想は今日に至るまで定着していません。OSベンダーが未署名アプリに対して警告画面を出し、囲い込みを試みても、開発者やユーザーは警告の回避策を共有して従来の自由な導入経路を使い続けています。&lt;/p&gt;&#10;&lt;p&gt;この差を生んだ最大の要因は、プラットフォームの初期条件と技術的制約の違いです。スマートフォンは最初から「ストアを通さなければアプリが入らない」という白紙の状態で市場を形成しました。対してPCには、数十年にわたり築き上げられたWebからの自由なインストーラー配布という商慣習がすでに完成していました。&lt;/p&gt;&#10;&lt;p&gt;さらに技術面では、ストアが課すサンドボックス規制がPC用ソフトウェアの特性と致命的に衝突しました。システム深部へのアクセスや高度な連携を必要とするプロ向けツールやユーティリティは、サンドボックス内に閉じ込められると本来の機能を発揮できません。結果として「ストア版は機能が削られた劣化版」となり、開発者は二重管理のコストを嫌ってWeb直販へと回帰していきました。知名度のあるソフトウェアにとって、外部決済なら数パーセントで済む手数料を、あえて15〜30パーセントもプラットフォーマーに上納する経済的合理性も存在しませんでした。&lt;/p&gt;&#10;&lt;h2 id="泥臭いwin32-apiの保守こそが最強の参入障壁である"&gt;泥臭いWin32 APIの保守こそが最強の参入障壁である&#10;&lt;/h2&gt;&lt;p&gt;Microsoftの歴史を振り返ると、同社は自らの最大の強みであるはずのWin32 APIを軽視し、モダンなフレームワークへの置き換えを幾度となく試みては失敗を繰り返してきました。開発現場からすれば、30年分の互換性と例外処理を抱え続けるWin32のメンテナンスは過酷な泥臭い仕事であり、セキュリティ上の構造的欠陥も抱えています。&lt;/p&gt;&#10;&lt;p&gt;しかし、ビジネスの本質は「誰もがやりたがらない面倒で困難な仕事を引き受けること」にこそ莫大な対価が発生するという点にあります。世界中の企業や産業現場がWindowsにライセンス料を支払い続ける真の理由は、最新の洗練されたUIではなく、昔作った業務システムや専用ツールが最新のOSでも寸分違わず動作するという圧倒的な後方互換性にあります。&lt;/p&gt;&#10;&lt;p&gt;セキュリティ対策はネットワークの分離やEDRの導入、仮想化などによってユーザー側で担保できますが、OSが提供するAPIの完全な後方互換性だけはユーザー側で自前で用意することが不可能です。かつてGoogleが洗練されたWeb技術とクラウドを武器にChromeOSで挑みながらもPCの牙城を崩せなかったのは、この無数の周辺機器やレガシー資産を力技で動かし続ける泥臭い互換性の壁を突破できなかったためです。&lt;/p&gt;&#10;&lt;h2 id="他社への羨望と逃げられない顧客への甘えが生む迷走"&gt;他社への羨望と「逃げられない顧客」への甘えが生む迷走&#10;&lt;/h2&gt;&lt;p&gt;現在のWindowsは、スタートメニューの広告枠化、デフォルトブラウザを&lt;code&gt;Microsoft Edge&lt;/code&gt;へ誘導する執拗な引き止め、あるいは利用価値が形骸化したMicrosoft Storeのゴーストタウン化など、自らOSとしての品位と信頼を削るような施策が目立ちます。&lt;/p&gt;&#10;&lt;p&gt;この迷走の根底には、Appleのアプリ手数料収入やGoogleの広告モデルに対する経営陣の強烈な羨望と、すでに全世界に行き渡りユーザー数が増加しない飽和状態への焦りがあります。そして何より、「どれだけ改悪しても、ユーザーはWin32資産の依存からMacやLinuxへ逃げられない」という足元を見た構造的な甘えが存在します。&lt;/p&gt;&#10;&lt;p&gt;しかし、道具としての黒子に徹するべきOSが、自社のサービスや広告をねじ込むためのメディアへと変質したことで、ユーザーが抱く感情は愛着や信頼から「仕方なく使わされている消極的な依存」へと劣化しています。泥臭い仕事によって築き上げた世界最強の参入障壁を持ちながら、他社のビジネスの表面的な模倣に走り、OS自体の価値を自ら毀損し続ける姿勢は、巨大プラットフォーマーが陥った最も皮肉なジレンマと言えます。&lt;/p&gt;&#10;</description></item><item><title>シングルバイナリと分散運用で考える「スケーリングさせない」アーキテクチャ設計論</title><link>https://ai.hack-le.com/%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%81%A8%E5%88%86%E6%95%A3%E9%81%8B%E7%94%A8%E3%81%A7%E8%80%83%E3%81%88%E3%82%8B%E3%80%8C%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AA/</link><pubDate>Tue, 25 Aug 2026 21:05:49 +0900</pubDate><guid>https://ai.hack-le.com/%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%81%A8%E5%88%86%E6%95%A3%E9%81%8B%E7%94%A8%E3%81%A7%E8%80%83%E3%81%88%E3%82%8B%E3%80%8C%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AA/</guid><description>&lt;h2 id="dockerを巡る違和感とネイティブ実行の合理性"&gt;Dockerを巡る違和感とネイティブ実行の合理性&#10;&lt;/h2&gt;&lt;p&gt;個人開発において、GoやRustによるシングルバイナリの生成と、データストアとしてのSQLiteを採用していると、Dockerの導入に対して常に一定の疑問がつきまといます。仮想化によるオーバーヘッドやビルド手順の複雑化、ボリュームの管理コストを支払ってまで、環境の分離や統一を求める動機が薄いからです。&lt;/p&gt;&#10;&lt;p&gt;一般にDockerのメリットとして挙げられる環境汚染の防止やクロスプラットフォーム対応は、適切な言語選定やPure Go/Pure Rustによる依存関係の排除によって、アーキテクチャのレベルで事前に回避できます。CGOなどのC言語ライブラリ依存や特殊な共有ライブラリが存在せず、OSネイティブのバイナリを単一ファイルとして配置できるのであれば、Dockerデーモンを挟まずに直接実行する方が開発体験もデプロイ手順も極めて軽快になります。&lt;/p&gt;&#10;&lt;p&gt;もちろん、Cloud RunやAWS ECSのようにコンテナイメージをデプロイ単位とするPaaSを利用する場合や、外部のミドルウェアを複数束ねて構成を完全にコード化したい場合にはDockerの価値が生まれます。しかし、Linux向けのバイナリをクロスコンパイルしてサーバーに転送し、&lt;code&gt;systemd&lt;/code&gt; 等で常駐させるだけで運用が完全に成立している段階では、仮想化レイヤーを挟むことは余計な複雑性を持ち込むだけに過ぎません。&lt;/p&gt;&#10;&lt;h2 id="スケーリングを拒絶する制約とセルフホストモデル"&gt;スケーリングを拒絶する制約とセルフホストモデル&#10;&lt;/h2&gt;&lt;p&gt;アプリケーションの提供形態を考える際、当初から中央集権的なマルチテナントSaaSを目指して大規模化を前提に設計するのか、それとも独立して動作する道具として設計するのかによって、アーキテクチャの選択は根本から分かれます。&lt;/p&gt;&#10;&lt;p&gt;ここで有効に機能するのが、&lt;strong&gt;スケーリングするほどの規模で運用させない&lt;/strong&gt;という意図的な制約です。1台のサーバーや限られたリソースの中で収容人数や定員を厳格に決め、それ以上の規模を求めないという割り切りを行うことで、マイクロサービス化や分散トランザクション、キャッシュの同期といった過度な複雑性の侵入を物理的に排除できます。現代のハードウェア性能は十分に高いため、適切に最適化された単一プロセスとSQLiteがあれば、1台のマシンでも実用上十分なトラフィックを処理することが可能です。&lt;/p&gt;&#10;&lt;p&gt;もしサービスを広く普及させたいのであれば、開発者自身が巨大な単一インフラを抱えて何十万人もの面倒を見る必要はありません。関心を持った利用者がそれぞれバイナリをダウンロードし、自身の持つリソースの範囲内で自律した管理者になればよいという結論に至ります。このセルフホスト前提のモデルに倒すことで、開発者側はインフラコストや常時監視、データ分離の重責から解放され、利用者は自身のデータ主権を手元に確保できるようになります。&lt;/p&gt;&#10;&lt;h2 id="プロセス隔離の現実と本質的なセキュリティ"&gt;プロセス隔離の現実と本質的なセキュリティ&#10;&lt;/h2&gt;&lt;p&gt;コンテナを導入する動機としてプロセス隔離（サンドボックス化）が挙げられることがありますが、教科書的な正論と運用上のリアリティの間には乖離が存在します。&lt;/p&gt;&#10;&lt;p&gt;Dockerなどのコンテナ機構は、本質的にはLinuxカーネルの機能（Namespaces、cgroups、seccompなど）を扱いやすくまとめた仕組みです。自分が書いたコードを自身が管理する専用環境で動かす範囲においては、一般ユーザー権限での実行や、&lt;code&gt;systemd&lt;/code&gt; のサンドボックス機能（&lt;code&gt;ProtectSystem=strict&lt;/code&gt; や &lt;code&gt;NoNewPrivileges=true&lt;/code&gt; など）を活用することで、コンテナデーモンを常駐させずともOSネイティブの機能だけで実用上十分な防御線を構築できます。&lt;/p&gt;&#10;&lt;p&gt;そもそも、脆弱性や悪意あるコードが存在する場合、コンテナに入れているから安全であるとは言えません。カーネル脆弱性を突いたコンテナエスケープのリスクは常に存在し、たとえホストOSに脱出されずとも、コンテナ内の環境変数に置かれた秘密鍵やマウントされたSQLiteファイル自体はそのプロセスの権限で容易に窃取されます。根本的なセキュリティは、入力値の検証や依存関係の最小化といった&lt;strong&gt;コード自体の規律&lt;/strong&gt;によって担保されるものであり、コンテナは粗雑な設計を帳消しにする魔法の盾ではありません。&lt;/p&gt;&#10;&lt;h2 id="プラットフォームの全滅と分散型のリスクヘッジ"&gt;プラットフォームの全滅と分散型のリスクヘッジ&#10;&lt;/h2&gt;&lt;p&gt;サーバーの管理下には常に侵害のリスクが存在しますが、システム全体として最も強固なリスクヘッジは、防御壁を何重にも厚くした単一の巨大要塞を作ることではなく、&lt;strong&gt;サーバーも管理者もバラバラに分散させること&lt;/strong&gt;です。&lt;/p&gt;&#10;&lt;p&gt;これは「個人ブログ」と「中央集権的なプラットフォーム」の対比によく現れます。個別の個人ブログはセキュリティやリソースの観点から個別に停止させることが容易に見えますが、世界中に散らばる無数の個人ブログを一度に全滅させることは原理的に不可能です。一方で、巨大なプラットフォームは個々の防御力が高く見えても、運営企業の倒産や規約変更、認証基盤への攻撃によって、数億人分のデータや発信拠点が一夜にして同時に消滅する全滅シナリオを常に内包しています。&lt;/p&gt;&#10;&lt;p&gt;1箇所にデータを集中させた中央サーバーは、攻撃者にとって最も費用対効果の高い標的となります。これに対し、独立したノードが分散していれば、ある管理者のサーバーが侵害されたり設定ミスで停止したりしても、その被害範囲は局所的に閉じたまま保たれます。&lt;/p&gt;&#10;&lt;p&gt;完璧に安全な中央サーバーを構築することを目指すのではなく、どこかのサーバーが破綻することを前提として、全体が共倒れしない疎結合な自立分散環境を作る。この思想に立つとき、軽量なシングルバイナリとSQLiteによる最小構成のアプリケーションは、最も頑健で理にかなった設計の答えとなります。&lt;/p&gt;&#10;</description></item><item><title>「モダン」という名の過剰な抽象化に奪われた時間と、道具の主権を取り戻すということ</title><link>https://ai.hack-le.com/%E3%80%8C%E3%83%A2%E3%83%80%E3%83%B3%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E5%90%8D%E3%81%AE%E9%81%8E%E5%89%B0%E3%81%AA%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%81%AB%E5%A5%AA%E3%82%8F%E3%82%8C%E3%81%9F%E6%99%82/</link><pubDate>Tue, 25 Aug 2026 21:02:03 +0900</pubDate><guid>https://ai.hack-le.com/%E3%80%8C%E3%83%A2%E3%83%80%E3%83%B3%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E5%90%8D%E3%81%AE%E9%81%8E%E5%89%B0%E3%81%AA%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%81%AB%E5%A5%AA%E3%82%8F%E3%82%8C%E3%81%9F%E6%99%82/</guid><description>&lt;h2 id="終わらない仕様への追従と消えない徒労感"&gt;終わらない仕様への追従と消えない徒労感&#10;&lt;/h2&gt;&lt;p&gt;10年以上付き合い続けてもなお、systemdやjournaldといったシステムに対する使いづらさの評価は変わらないままでした。Unixが培ってきた「ひとつのことをうまくやる」「プレーンテキストをパイプで繋ぐ」という思想から離れ、バイナリログの採用や機能の肥大化、ブラックボックス化が進んだ仕組みは、いくら時間をかけて習熟しても道具としての手触りの悪さが拭えません。&lt;/p&gt;&#10;&lt;p&gt;2010年代以降、IT業界では「これがモダンで堅牢な未来の標準だ」という号令のもと、トップダウン的な移行が幾度となく繰り返されてきました。Waylandへの移行に伴う長年の摩擦や機能の再実装も、根底にある構図は同じです。古い設計の課題を解決するという名目で導入された新しい仕組みは、往々にして以前よりも複雑で、特定のアーキテクチャや設定作法への過度な依存を強いる結果となりました。&lt;/p&gt;&#10;&lt;p&gt;普遍的な計算機科学の原理とは異なり、誰かの独善的な設計思想に合わせて作られた短命な仕様を学ぶ作業は、知識としての積み上がりがありません。数年で陳腐化する流行の仕様変更に振り回され、不条理な仕様を回避するためのバッドノウハウばかりが増えていく現実は、真面目にキャッチアップを続けてきた者ほど強烈な徒労感を残します。&lt;/p&gt;&#10;&lt;h2 id="巨大な抽象化の果てに開かれるindexhtml"&gt;巨大な抽象化の果てに開かれる&lt;code&gt;index.html&lt;/code&gt;&#10;&lt;/h2&gt;&lt;p&gt;この過剰な抽象化と車輪の再発明の構図は、OSレイヤーにとどまらず、Webフロントエンドやインフラに至るまで広く蔓延しています。「既存のやり方には深刻な脆弱性があり、レンダリングも古い」という論理で、無数の依存パッケージ、多重のビルドパイプライン、独自のDSL、中間トランスパイラが次々と導入されてきました。&lt;/p&gt;&#10;&lt;p&gt;しかし、膨大な計算資源と人間の可処分時間を注ぎ込み、巨大な&lt;code&gt;node_modules&lt;/code&gt;を展開した果てに実現されたことの本質は、昔と変わらずただの&lt;code&gt;index.html&lt;/code&gt;を開くことでした。&lt;/p&gt;&#10;&lt;p&gt;画面に数行のテキストを表示するだけのために、数千行の依存関係を解決し、メモリを限界まで消費してビルドを通すという行為は、目的と手段が完全に逆転しています。何重ものラッパーで包み込んだ結果、ブラウザ本来の標準機能が損なわれ、エラー発生時には難読化されたコードのデバッグを強いられるという欺瞞が常態化しました。&lt;/p&gt;&#10;&lt;h2 id="他人のエゴから離れ道具の主権を取り戻す"&gt;他人のエゴから離れ、道具の主権を取り戻す&#10;&lt;/h2&gt;&lt;p&gt;「学べばわかる」「理解できないのは知識が足りないからだ」という言説は、設計の欠陥や運用の摩擦をユーザー側の努力不足に転嫁する方便にすぎません。そして、どれだけ熱心に最新の流行を推奨した人間であっても、数十年後にそれが「時代の徒花だった」と判明したときに、他人の浪費された人生に対して何の責任も取ってはくれません。&lt;/p&gt;&#10;&lt;p&gt;普遍的な知恵の獲得ではなく、他人が気まぐれに作り出した過剰な中間層のメンテナンスに人生のリソースを費やし続ける必要はありません。&lt;/p&gt;&#10;&lt;p&gt;これからの選択として重要なのは、他人の敷いたレールに無批判に従うことではなく、&lt;strong&gt;自分が納得でき、手元で完全にコントロールできる道具&lt;/strong&gt;を選ぶことです。枯れていて泥臭くても、いざというときに手触りよく直せる仕組みや、自分にとって真に価値のある対象にのみ時間を使うという姿勢こそが、不可逆な自分の人生を守るための正当な防衛線となります。&lt;/p&gt;&#10;</description></item><item><title>Dockerで放置された不要なコンテナを安全かつ確実に削除・掃除する手順</title><link>https://ai.hack-le.com/docker%E3%81%A7%E6%94%BE%E7%BD%AE%E3%81%95%E3%82%8C%E3%81%9F%E4%B8%8D%E8%A6%81%E3%81%AA%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%92%E5%AE%89%E5%85%A8%E3%81%8B%E3%81%A4%E7%A2%BA%E5%AE%9F%E3%81%AB/</link><pubDate>Mon, 24 Aug 2026 11:38:11 +0900</pubDate><guid>https://ai.hack-le.com/docker%E3%81%A7%E6%94%BE%E7%BD%AE%E3%81%95%E3%82%8C%E3%81%9F%E4%B8%8D%E8%A6%81%E3%81%AA%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%92%E5%AE%89%E5%85%A8%E3%81%8B%E3%81%A4%E7%A2%BA%E5%AE%9F%E3%81%AB/</guid><description>&lt;p&gt;サーバー上で &lt;code&gt;docker ps&lt;/code&gt; を実行した際、過去に起動したまま数ヶ月間放置されているコンテナを見つけることがあります。不要になったコンテナはリソースを圧迫する要因となるため、適切なコマンドを用いて速やかに削除し、環境をクリーンな状態に保つことが望ましいです。本記事では、稼働中のコンテナを停止・削除する手順と、関連する不要リソースを一括で整理する方法をまとめます。&lt;/p&gt;&#10;&lt;h2 id="稼働中コンテナの停止と削除"&gt;稼働中コンテナの停止と削除&#10;&lt;/h2&gt;&lt;p&gt;Dockerコンテナは通常、稼働している状態では &lt;code&gt;docker rm&lt;/code&gt; による削除ができません。確実に対処するためには、まずコンテナを停止してから削除するか、強制削除オプションを指定して処理します。&lt;/p&gt;&#10;&lt;p&gt;手早く1行で済ませたい場合は、 &lt;strong&gt;-f オプションを付与した強制削除&lt;/strong&gt;を実行するのが便利です。コンテナIDまたはコンテナ名を指定して以下のように実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker rm -f &amp;lt;CONTAINER_ID_OR_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;実行中の処理を安全に終了させてから削除したい場合は、段階を踏んで停止と削除を個別に実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker stop &amp;lt;CONTAINER_ID_OR_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker rm &amp;lt;CONTAINER_ID_OR_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらのコマンドを実行することで、対象のコンテナ本体がホスト環境から安全に取り除かれます。&lt;/p&gt;&#10;&lt;h2 id="関連リソースの整理と一括クリーンアップ"&gt;関連リソースの整理と一括クリーンアップ&#10;&lt;/h2&gt;&lt;p&gt;コンテナ本体を削除しても、データベースの永続化データが保存されているボリュームや、コンテナの元となったイメージファイルはストレージ上に残り続けます。長期間放置されていた環境では、こうした付随リソースもあわせて整理することが重要です。&lt;/p&gt;&#10;&lt;p&gt;データベース等の不要なボリュームのみを整理したい場合は &lt;code&gt;docker volume prune -f&lt;/code&gt; を使用し、使われていないイメージを完全に削除したい場合は &lt;code&gt;docker image prune -a -f&lt;/code&gt; を実行します。&lt;/p&gt;&#10;&lt;p&gt;もし開発環境の全体をリセットし、停止中のコンテナ、使用されていないネットワーク、ボリューム、イメージを&lt;strong&gt;まとめて一括で掃除したい場合&lt;/strong&gt;は、以下のコマンドを実行することでディスク容量を大幅に解放できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker system prune --volumes -f&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不要になったコンテナとその関連データを適切に破棄することで、サーバーのリソース浪費を防ぎ、安定した運用環境を維持できます。&lt;/p&gt;&#10;</description></item><item><title>Mac miniをホストにしてAntigravityの作業環境を複数マシンでシームレスに引き継ぐ方法</title><link>https://ai.hack-le.com/mac-mini%E3%82%92%E3%83%9B%E3%82%B9%E3%83%88%E3%81%AB%E3%81%97%E3%81%A6antigravity%E3%81%AE%E4%BD%9C%E6%A5%AD%E7%92%B0%E5%A2%83%E3%82%92%E8%A4%87%E6%95%B0%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%A7%E3%82%B7/</link><pubDate>Mon, 24 Aug 2026 07:41:46 +0900</pubDate><guid>https://ai.hack-le.com/mac-mini%E3%82%92%E3%83%9B%E3%82%B9%E3%83%88%E3%81%AB%E3%81%97%E3%81%A6antigravity%E3%81%AE%E4%BD%9C%E6%A5%AD%E7%92%B0%E5%A2%83%E3%82%92%E8%A4%87%E6%95%B0%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%A7%E3%82%B7/</guid><description>&lt;p&gt;Google AntigravityでAIコーディングを行う際、課題となるのが「チャットセッションや作業状態が単一マシン内に閉じてしまう」という点です。メインのデスクトップMacで進めていた作業を、手元のWindowsノートPCや別端末からそのまま継続しようとすると、文脈の引き継ぎが難しくなります。&lt;/p&gt;&#10;&lt;p&gt;この問題を解決するため、常時稼働させている&lt;strong&gt;デスクトップMac（Mac mini）を開発ホストとして集約&lt;/strong&gt;し、ノートPC等の別端末からはSSH経由でAntigravity CLI（&lt;code&gt;agy&lt;/code&gt;）&lt;strong&gt;と&lt;/strong&gt;&lt;code&gt;tmux&lt;/code&gt;を組み合わせて操作する構成を採用することにしました。本記事では、この構成を選定した理由と、環境構築にあたって遭遇したトラブルの回避手順を備忘録としてまとめます。&lt;/p&gt;&#10;&lt;h2 id="なぜmacホストantigravity-cliの構成を選んだのか"&gt;なぜMacホスト＋Antigravity CLIの構成を選んだのか&#10;&lt;/h2&gt;&lt;p&gt;最初に検討したのは、GUI版Antigravity（VS Codeフォーク）の内蔵Remote-SSH拡張機能を使ってMacに接続する方法でした。しかし、実際に接続を試みると内部スクリプトがLinux環境を前提としたコマンド（&lt;code&gt;flock&lt;/code&gt; 等）に依存しており、現時点ではmacOSをSSHホストとしてGUI接続することはできません。&lt;/p&gt;&#10;&lt;p&gt;また、自前の低スペックLinuxサーバーをホストにする案もありましたが、重いビルド処理やコンテナの運用を考慮すると、CPU性能やメモリに余裕があるMac miniを活用するほうが快適です。&lt;/p&gt;&#10;&lt;p&gt;そこで、GUIのリモート接続に拘るのではなく、CUI環境で完結する公式CLIツール&lt;code&gt;agy&lt;/code&gt;&lt;strong&gt;を採用し、ターミナルマルチプレクサである&lt;/strong&gt;&lt;code&gt;tmux&lt;/code&gt;上で稼働させるアプローチに落ち着きました。この構成であれば、OSの互換性問題を完全に回避しつつ、どの端末からでも同一のセッションに再接続してAIとの対話を再開できます。&lt;/p&gt;&#10;&lt;h2 id="鍵認証とセッション分離の注意点"&gt;鍵認証とセッション分離の注意点&#10;&lt;/h2&gt;&lt;p&gt;構築時にまず直面したのが、SSH接続時の認証エラーでした。サーバー上でGiteaなどをホストしている場合、Git操作用に登録された公開鍵でログインを試みるとシェルアクセスが拒否されます。そのため、通常のシェルログイン専用となる新しいSSH鍵ペアを作成し、接続設定で明示的に指定する必要があります。&lt;/p&gt;&#10;&lt;p&gt;クライアント端末（Windows等）で開発用の鍵を生成し、ホスト側の &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; に登録します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 鍵ペアの生成&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh-keygen -t ed25519 -f ~/.ssh/id_dev_server -C &lt;span class="s2"&gt;&amp;#34;dev-login&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;クライアント側の &lt;code&gt;~/.ssh/config&lt;/code&gt; には、他の鍵が自動送信されないよう &lt;code&gt;IdentitiesOnly yes&lt;/code&gt; を含めて設定を記述します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host dev-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HostName 192.168.0.xxx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User your_user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IdentityFile ~/.ssh/id_dev_server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IdentitiesOnly yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Windows環境から接続する場合は、PowerShellネイティブのコンソールよりも&lt;strong&gt;WSL2（Linux環境）経由で接続したほうが、文字コード（UTF-8）や端末制御（PTY）の互換性が高く、表示崩れや文字化けを起こさず安定&lt;/strong&gt;します。&lt;/p&gt;&#10;&lt;h2 id="tmuxとagyによるセッション永続化と運用"&gt;tmuxとagyによるセッション永続化と運用&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;agy&lt;/code&gt; 単体で起動するとSSH切断時にセッションが切れてしまうため、ホスト側のMac上で &lt;code&gt;tmux&lt;/code&gt; を起動し、その中で対話セッションを実行します。&lt;/p&gt;&#10;&lt;p&gt;ホストのMac側では、マウススクロールの有効化と文字コードの安定化のため、あらかじめ &lt;code&gt;~/.tmux.conf&lt;/code&gt; に設定を追加しておきます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -g mouse on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -g default-terminal &lt;span class="s2"&gt;&amp;#34;screen-256color&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;日常的な運用で必要な操作はシンプルです。作業を開始する際は、既存セッションへの再接続（存在しない場合は新規作成）をまとめて行うワンライナーで接続します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tmux attach -t dev &lt;span class="o"&gt;||&lt;/span&gt; tmux new -s dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;セッション内で &lt;code&gt;agy&lt;/code&gt; を起動すれば、直前までのプロジェクト構造を読み取った状態でAIコーディングを開始できます。過去の会話セッションを再開したい場合は、起動時に &lt;code&gt;--resume&lt;/code&gt; フラグを付与するか、対話画面で &lt;code&gt;/resume&lt;/code&gt; コマンドを実行して履歴を選択します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 直前の対話を再開して起動&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;agy --resume&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;作業を中断したい時は、キーボードで &lt;code&gt;Ctrl + b&lt;/code&gt; を押した後に &lt;code&gt;d&lt;/code&gt; を押してデタッチします。これによりMac側でプロセスが保持され、後から別のノートPCを開いて再び &lt;code&gt;tmux attach -t dev&lt;/code&gt; を実行するだけで、&lt;strong&gt;全く同じ画面・対話状態へと即座に復帰&lt;/strong&gt;できます。&lt;/p&gt;&#10;</description></item><item><title>Emacsを常にターミナル内（-nw）で起動させる設定とsudo実行時の対策</title><link>https://ai.hack-le.com/emacs%E3%82%92%E5%B8%B8%E3%81%AB%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E5%86%85%EF%BC%88-nw%EF%BC%89%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%82%8B%E8%A8%AD%E5%AE%9A%E3%81%A8sudo/</link><pubDate>Sat, 22 Aug 2026 17:28:18 +0900</pubDate><guid>https://ai.hack-le.com/emacs%E3%82%92%E5%B8%B8%E3%81%AB%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E5%86%85%EF%BC%88-nw%EF%BC%89%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%82%8B%E8%A8%AD%E5%AE%9A%E3%81%A8sudo/</guid><description>&lt;p&gt;GUI環境が整っている端末であっても、エディタはターミナル内部で軽快に動かしたいという場面は多くあります。Emacsをターミナル内で起動するには通常 &lt;code&gt;-nw&lt;/code&gt; オプションを付与しますが、コマンドを実行するたびに入力するのは手間がかかります。そこで、常にターミナル内で開くための設定と、&lt;code&gt;sudo&lt;/code&gt; を付与した際にもその挙動を維持する方法、さらに安全に管理者権限で編集するための代替アプローチを整理します。&lt;/p&gt;&#10;&lt;h2 id="常にターミナル内でemacsを起動するエイリアス設定"&gt;常にターミナル内でEmacsを起動するエイリアス設定&#10;&lt;/h2&gt;&lt;p&gt;コマンド入力を省略する最もシンプルな手段は、利用しているシェルの設定ファイル（Bashであれば &lt;code&gt;~/.bashrc&lt;/code&gt;、Zshであれば &lt;code&gt;~/.zshrc&lt;/code&gt;）にエイリアスを登録することです。&lt;/p&gt;&#10;&lt;p&gt;設定ファイルへ以下のように記述します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;emacs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;emacs -nw&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;記述後に &lt;code&gt;source ~/.bashrc&lt;/code&gt; や &lt;code&gt;source ~/.zshrc&lt;/code&gt; を実行して設定を再読み込みすれば、以降は &lt;code&gt;emacs&lt;/code&gt; と入力するだけで自動的に &lt;code&gt;-nw&lt;/code&gt; が付与された状態で起動するようになります。なお、稀にGUIウィンドウでEmacsを立ち上げたい状況が発生した場合は、コマンドの先頭にバックスラッシュを付与して &lt;code&gt;\emacs&lt;/code&gt; と実行することで、登録したエイリアスを一時的に無効化して起動できます。&lt;/p&gt;&#10;&lt;h2 id="sudo実行時にエイリアスを展開させる工夫"&gt;sudo実行時にエイリアスを展開させる工夫&#10;&lt;/h2&gt;&lt;p&gt;一般ユーザー権限ではエイリアスによって意図通りに動作しますが、システムファイルの編集などで &lt;code&gt;sudo emacs&lt;/code&gt; を実行した途端、ふたたびGUI版が立ち上がってしまう問題に直面します。これは、&lt;code&gt;sudo&lt;/code&gt; コマンドがデフォルトではシェルのエイリアスを展開せず、後続の引数をそのまま実行ファイル名として解釈するためです。&lt;/p&gt;&#10;&lt;p&gt;この仕様を回避するには、シェル設定ファイルに以下のエイリアスを追加します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sudo &amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ポイントは、末尾に&lt;strong&gt;半角スペース&lt;/strong&gt;を含めている点です。多くのシェルには「エイリアス展開後の文字列が空白で終わっている場合、続く次の単語に対してもエイリアス展開を試みる」という仕様が備わっています。これを利用することで、&lt;code&gt;sudo emacs&lt;/code&gt; と入力した際にも直後の &lt;code&gt;emacs&lt;/code&gt; が &lt;code&gt;emacs -nw&lt;/code&gt; へと正常に展開されるようになります。&lt;/p&gt;&#10;&lt;h2 id="安全に管理者権限で編集するsudoeditの活用"&gt;安全に管理者権限で編集するsudoeditの活用&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;sudo emacs&lt;/code&gt; でエイリアスを効かせる方法のほかに、セキュリティの観点から推奨される手段として &lt;code&gt;sudoedit&lt;/code&gt;（または &lt;code&gt;sudo -e&lt;/code&gt;）の利用が挙げられます。&lt;code&gt;sudo emacs&lt;/code&gt; はEmacsプロセス全体をroot権限で動作させるため、万一エディタ内で意図しない処理が走った際のリスクが高まります。対して &lt;code&gt;sudoedit&lt;/code&gt; は、対象ファイルの複製を一時ファイルとして一般ユーザー権限のエディタで編集し、保存・終了時にのみ管理者権限で元のファイルへ上書きする仕組みをとっています。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;sudoedit&lt;/code&gt; で起動するエディタをEmacsのCUIモードにするには、シェルの設定ファイルで環境変数を指定します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;emacs -nw&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;VISUAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;emacs -nw&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;設定反映後は、&lt;code&gt;sudoedit /path/to/file&lt;/code&gt; のようにファイルを指定して編集します。root権限でのエディタ直接実行を避けつつ、普段と同じターミナル環境のEmacsで安全にシステムファイルを更新できます。&lt;/p&gt;&#10;</description></item><item><title>LinuxデスクトップにおけるWayland移行の政治学とX11の実用主義</title><link>https://ai.hack-le.com/linux%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bwayland%E7%A7%BB%E8%A1%8C%E3%81%AE%E6%94%BF%E6%B2%BB%E5%AD%A6%E3%81%A8x11%E3%81%AE%E5%AE%9F%E7%94%A8/</link><pubDate>Sat, 22 Aug 2026 02:14:25 +0900</pubDate><guid>https://ai.hack-le.com/linux%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bwayland%E7%A7%BB%E8%A1%8C%E3%81%AE%E6%94%BF%E6%B2%BB%E5%AD%A6%E3%81%A8x11%E3%81%AE%E5%AE%9F%E7%94%A8/</guid><description>&lt;h2 id="商用ベンダーの都合とデスクトップの政治学"&gt;商用ベンダーの都合とデスクトップの政治学&#10;&lt;/h2&gt;&lt;p&gt;Linuxエコシステムにおいて語られる&lt;code&gt;Wayland&lt;/code&gt;への移行論は、純粋な技術的必然性というよりも、Red HatやCanonicalをはじめとする商用ディストリビューションベンダーの&lt;strong&gt;企業都合とビジネス戦略&lt;/strong&gt;に強く牽引されています。これらのエンタープライズ企業にとって、クラウドやデータセンターで稼働するサーバー基盤とデスクトップ基盤の低レイヤーを統一し、肥大化した&lt;code&gt;Xorg&lt;/code&gt;の保守コストを削減することは合理的な判断です。しかし、その企業側の損益計算に基づいた方針が、あたかもLinuxコミュニティ全体の普遍的な正解であるかのように語られることには大きな欺瞞が存在します。&lt;/p&gt;&#10;&lt;p&gt;現実に目を向ければ、Ubuntuにおける&lt;code&gt;Wayland&lt;/code&gt;デフォルト化の度重なる撤回や延期、&lt;code&gt;NVIDIA&lt;/code&gt;製プロプライエタリドライバとの長年にわたる規格対立（&lt;code&gt;GBM&lt;/code&gt;対&lt;code&gt;EGLStreams&lt;/code&gt;）など、移行は極めて難航してきました。これらはコード実装の難易度を超えた、仕様の主導権争いと責任分界点の押し付け合いという&lt;strong&gt;政治的な摩擦&lt;/strong&gt;の結果です。&lt;/p&gt;&#10;&lt;h2 id="中央集権の不在と現場のリアリズム"&gt;中央集権の不在と現場のリアリズム&#10;&lt;/h2&gt;&lt;p&gt;WindowsやmacOSのようなプロプライエタリOSは、単一の巨大企業が垂直統合で仕様を決定し、サードパーティやユーザーに強制することで急速なアーキテクチャの刷新を実現します。一方、Linuxにおいてはカーネル開発こそリーナス・トーバルズの厳格な統治下にありますが、ユーザー空間やGUIスタックには全体を統制する最高権威が存在しません。&lt;/p&gt;&#10;&lt;p&gt;この分散型の構造において、上流のメンテナや一部の巨大ベンダーがセキュリティ至上主義に基づいて設計を急進させても、現場の実用的なニーズと乖離していれば強い反発が生じます。かつての&lt;code&gt;systemd&lt;/code&gt;を巡る分断と同様に、&lt;code&gt;Wayland&lt;/code&gt;の隔離モデルによってスクリーンショット、画面共有、キーリマップ、高度な日本語入力といった日常的な機能が制限され、それを解決するために&lt;code&gt;xdg-desktop-portal&lt;/code&gt;や&lt;code&gt;PipeWire&lt;/code&gt;といった追加の抽象レイヤーを幾重にも重ねる事態は、道具としての簡潔さを損なう本末転倒なユーザー体験を生み出しました。&lt;/p&gt;&#10;&lt;h2 id="枯れた技術の実用性と真のサステナビリティ"&gt;枯れた技術の実用性と真のサステナビリティ&#10;&lt;/h2&gt;&lt;p&gt;OSの選択における唯一の正当性は、利用者の目的やハードウェアの制約に適合し、日々の作業を確実に完遂できるかどうかにあります。10年以上前のPCであっても、SSDと十分なメモリがあれば現代の日常的な事務作業やプログラミングを十分にこなすことができます。Microsoftが&lt;code&gt;Windows 11&lt;/code&gt;で課したような恣意的な要件引き上げによるハードウェアの切り捨てに対し、軽量なデスクトップ環境（&lt;code&gt;Xfce&lt;/code&gt;など）と&lt;code&gt;X11&lt;/code&gt;を組み合わせて既存の計算資源を限界まで使い倒すことこそが、&lt;strong&gt;最も本質的な持続可能性&lt;/strong&gt;です。&lt;/p&gt;&#10;&lt;p&gt;長年の運用を経て枯れ、仕様変更で壊れることのない&lt;code&gt;X11&lt;/code&gt;環境は、不要なトラブルシューティングからユーザーを解放し、設定通りの安定した動作を提供し続けます。外部のトレンドや特定企業のロードマップに盲従せず、手元の環境に最適化された構成を維持することは、オープンソースが本来担保している自由と実用主義に完全に合致します。&lt;/p&gt;&#10;&lt;h2 id="主流派言説とai生成の欺瞞"&gt;主流派言説とAI生成の欺瞞&#10;&lt;/h2&gt;&lt;p&gt;Web上に流通する技術情報や大手IT企業のマーケティング、そしてそれらを学習データとして出力するAIの言説には、統計的多数派や商業的勝者の論理を無批判に増幅させる&lt;strong&gt;構造的なバイアス&lt;/strong&gt;が働いています。中立や客観性を掲げながら、実際にはエンタープライズの意向を標準化の正義として垂れ流し、批判を受けると無責任に迎合を繰り返す態度は、道具としての知性の不在を示しています。&lt;/p&gt;&#10;&lt;p&gt;大量生成された薄い言説やプラットフォームの思惑に惑わされることなく、自身の用途における実利と安定性を見極め、自らのワークフローを自律的に統制し続ける姿勢こそが、計算機を扱う上で最も重要な規律です。&lt;/p&gt;&#10;</description></item><item><title>LinuxデスクトップにおけるWayland移行の実態と課題――X11廃止の背景にある技術的限界とベンダーの論理</title><link>https://ai.hack-le.com/linux%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bwayland%E7%A7%BB%E8%A1%8C%E3%81%AE%E5%AE%9F%E6%85%8B%E3%81%A8%E8%AA%B2%E9%A1%8C%E2%80%95%E2%80%95x11/</link><pubDate>Fri, 21 Aug 2026 04:37:01 +0900</pubDate><guid>https://ai.hack-le.com/linux%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bwayland%E7%A7%BB%E8%A1%8C%E3%81%AE%E5%AE%9F%E6%85%8B%E3%81%A8%E8%AA%B2%E9%A1%8C%E2%80%95%E2%80%95x11/</guid><description>&lt;h2 id="chatgpt-linux版に見るwaylandネイティブ対応の現状"&gt;ChatGPT Linux版に見るWaylandネイティブ対応の現状&#10;&lt;/h2&gt;&lt;p&gt;OpenAIがLinux向けに公開したデスクトップアプリのプレビュー版は、Ubuntu 26.04 LTSやFedoraといった最新のディストリビューションをターゲットに据えつつも、ネイティブWaylandのサポートは実験的扱いに留まっています。Ubuntu 26.04 LTSのようにデスクトップ環境としてWaylandのみを標準採用するOSであっても、アプリ自体は互換レイヤーである Xwayland を介して動作するため、ユーザーが起動や利用に困ることは基本的にありません。&lt;/p&gt;&#10;&lt;p&gt;しかし、なぜ巨大な開発リソースを持つ企業ですら、最初からネイティブWaylandに完全対応させないのかという疑問が生じます。この背景には、デスクトップアプリの多くが採用するElectronやChromiumの描画基盤である Ozone プラットフォームへの依存があります。アプリ個別の改修だけでなく、日本語IMEの入力制御やグローバルショートカット、ウィンドウ管理プロトコルの差異といった基盤側の課題が絡むため、ネイティブ化には相応の検証コストが伴います。互換レイヤーである Xwayland が極めて安定して機能している現状では、アプリ開発元にとってネイティブ対応の優先度が上がりにくいという実情があります。&lt;/p&gt;&#10;&lt;h2 id="なぜx11の継続は困難だったのか"&gt;なぜX11の継続は困難だったのか&#10;&lt;/h2&gt;&lt;p&gt;下位互換性や開発のしやすさを優先するならば「従来のX11のままでよいのではないか」という意見も根強く存在します。しかし、X11（Xorg）を維持し続けることには構造的な技術的限界が存在していました。X11は1980年代の設計思想を基礎としており、約40年にわたってパッチを積み重ねてきた結果、コードベースが極度に複雑化し、現代のハードウェア要件に追従できなくなっていました。&lt;/p&gt;&#10;&lt;p&gt;代表的な課題が、ディスプレイごとに異なるHiDPIスケーリングや可変リフレッシュレート、HDRへの対応、そして画面のテアリング防止です。これらを根本から破綻なく制御するには、プロトコル設計の刷新が不可欠でした。さらに決定打となったのがセキュリティモデルの欠如です。X11は同一セッション内のすべてのクライアントが他のウィンドウの入力や描画内容を取得・偽装できる構造になっており、近年のアプリケーションサンドボックス（FlatpakやSnapなど）やゼロトラスト前提のセキュリティ要件と根本的に衝突していました。&lt;/p&gt;&#10;&lt;h2 id="ディストリビューション企業の都合とプラットフォームの維持"&gt;ディストリビューション企業の都合とプラットフォームの維持&#10;&lt;/h2&gt;&lt;p&gt;技術的な理由に加え、Waylandへの移行を決定づけた最大の要因は、Red HatやCanonicalといった商用ディストリビューション企業の保守コストとビジネス上の都合にあります。Xorgサーバーの開発と保守を担ってきた主要エンジニアの大半は一般のボランティアではなく、これらの企業に雇用された技術者でした。Waylandスタックの拡張を進めながら、同時に老朽化したXorgサーバーを10年単位のエンタープライズ製品向けに二重保守し続けることは、企業の投資として限界を迎えていました。&lt;/p&gt;&#10;&lt;p&gt;加えて、エンタープライズ顧客や政府調達基準が求める厳格なセキュリティ認証をクリアするためにも、権限分離が担保されたWaylandへの一本化はベンダーにとって必須の選択でした。主要メンテナを抱える企業がXorgのメンテナンス停止とWaylandへの一本化を宣言したことで、代替のリソースを投じる第三者が現れない以上、ディストリビューション全体が追従せざるを得ない構造となっていました。&lt;/p&gt;&#10;&lt;p&gt;オープンソースのLinuxにはフォークの自由があるものの、グラフィックススタックのような極めて巨大で難解な低レイヤーの維持は、実質的にごく少数の企業の資金力と人的リソースに依存しています。その結果、主要ベンダーの自社リソースの最適化とエンタープライズ戦略という論理が、一般ユーザーやサードパーティの開発者に移行コストとして転嫁される構図が浮き彫りになっています。&lt;/p&gt;&#10;</description></item><item><title>LinuxにおけるWebカメラの認識確認</title><link>https://ai.hack-le.com/linux%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bweb%E3%82%AB%E3%83%A1%E3%83%A9%E3%81%AE%E8%AA%8D%E8%AD%98%E7%A2%BA%E8%AA%8D/</link><pubDate>Thu, 20 Aug 2026 23:13:27 +0900</pubDate><guid>https://ai.hack-le.com/linux%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bweb%E3%82%AB%E3%83%A1%E3%83%A9%E3%81%AE%E8%AA%8D%E8%AD%98%E7%A2%BA%E8%AA%8D/</guid><description>&lt;p&gt;Logicool C270nは標準的なUVC（USB Video Class）規格に準拠しているため、専用ドライバを手動で導入することなく、Linuxカーネル標準のドライバで即座に利用可能です。接続後はまず、システムが物理的にデバイスを認識しているか、またビデオデバイスファイルが正常に生成されているかを確認します。&lt;/p&gt;&#10;&lt;p&gt;端末で以下のコマンドを実行し、USBバス上にデバイスが検出されているかを確認します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsusb | grep -i logitech&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Logitech（Logicool）関連の出力が確認できたら、次にデバイスファイルの状態をチェックします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /dev/video*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;実行結果に &lt;strong&gt;/dev/video0&lt;/strong&gt;などのデバイスファイルが表示されていれば、OSレベルでの認識は完了しています。&lt;/p&gt;&#10;&lt;h2 id="映像カメラ機能の動作テスト"&gt;映像（カメラ）機能の動作テスト&#10;&lt;/h2&gt;&lt;p&gt;デバイスが認識されていることを確認した後は、実際に映像が取得できるかを検証します。GUI環境を利用している場合は、WebブラウザでWebカメラのテストサイトを開く方法が最も手軽です。デスクトップアプリケーションを用いる場合は、Cheeseなどのキャプチャツールやメディアプレイヤーのmpvを活用して直接ストリームを表示させます。&lt;/p&gt;&#10;&lt;p&gt;mpvを使用する場合は、以下のコマンドで手軽にカメラ映像のプレビュー画面を立ち上げることができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mpv /dev/video0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GUI環境がないCUI環境やサーバー環境では、fswebcamなどのCLIツールを利用して静止画をファイルへ保存することで、&lt;strong&gt;映像取得の可否を判定&lt;/strong&gt;できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fswebcam test.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存された画像ファイルを開き、撮影が正常に行われているかを確認します。&lt;/p&gt;&#10;&lt;h2 id="内蔵マイクの動作テスト"&gt;内蔵マイクの動作テスト&#10;&lt;/h2&gt;&lt;p&gt;C270nにはマイクが内蔵されているため、映像だけでなく音声入力のテストも合わせて実施しておく必要があります。ALSAのユーティリティコマンドを利用することで、マイクの認識状態の確認から録音・再生テストまでを簡潔に行えます。&lt;/p&gt;&#10;&lt;p&gt;まず、システムが録音デバイスとして認識しているかを一覧表示で確認します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;arecord -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一覧にUSBオーディオデバイスとして表示されていることを確認したら、実際に数秒間の音声をテスト録音します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;arecord -d 5 -f cd test.wav&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成された音声ファイルを再生し、内蔵マイクでクリアに&lt;strong&gt;音声が入力できているか確認&lt;/strong&gt;します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aplay test.wav&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>macOS 14.8.3におけるスクリーンショット保存先とファイル形式のJPG変更手順</title><link>https://ai.hack-le.com/macos-14-8-3%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E4%BF%9D%E5%AD%98%E5%85%88%E3%81%A8%E3%83%95%E3%82%A1%E3%82%A4/</link><pubDate>Sat, 31 Jan 2026 16:55:41 +0900</pubDate><guid>https://ai.hack-le.com/macos-14-8-3%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E4%BF%9D%E5%AD%98%E5%85%88%E3%81%A8%E3%83%95%E3%82%A1%E3%82%A4/</guid><description>&lt;p&gt;macOSの標準機能であるスクリーンショットは、初期設定において「デスクトップ」を保存先とし、ファイル形式には「PNG」が採用されている。本記事では、保存先の変更とファイル形式の変更について記述する。&lt;/p&gt;&#10;&lt;h2 id="環境"&gt;環境&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;項目&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;内容&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;OSバージョン&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;macOS 14.8.3&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;使用ツール&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ターミナル (Terminal.app)、スクリーンショットアプリ&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;目的&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ファイルサイズの軽量化およびディレクトリ管理の整理&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="スクリーンショットアプリによる直感的な保存場所の変更"&gt;スクリーンショットアプリによる直感的な保存場所の変更&#10;&lt;/h2&gt;&lt;p&gt;macOSには標準でスクリーンショットを管理するための専用インターフェースが備わっており、GUI操作のみで保存場所の変更が可能である。&lt;/p&gt;&#10;&lt;p&gt;キーボードの &lt;code&gt;Command&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;5&lt;/code&gt; を同時に押下し、画面下部にスクリーンショットツールバーを表示させる。このツールバー内に存在する「オプション」メニューをクリックすることで、保存先の候補が表示される。&lt;/p&gt;&#10;&lt;h2 id="ターミナルを利用したファイル形式のjpg化と詳細設定"&gt;ターミナルを利用したファイル形式のJPG化と詳細設定&#10;&lt;/h2&gt;&lt;p&gt;ファイル形式をPNGからJPGへ変更し、さらに保存場所をコマンドラインから厳密に指定するには、ターミナルでの操作が最も確実である。まず、LaunchpadやSpotlightから「ターミナル」を起動する。ファイル形式をJPGに変更するには、以下のコマンドを入力し、実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;defaults write com.apple.screencapture &lt;span class="nb"&gt;type&lt;/span&gt; jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、システムの環境設定ファイルを書き換えるものであり、&lt;code&gt;type&lt;/code&gt; の後には &lt;code&gt;png&lt;/code&gt;、&lt;code&gt;pdf&lt;/code&gt;、&lt;code&gt;tiff&lt;/code&gt;、&lt;code&gt;gif&lt;/code&gt; など任意の拡張子を指定できる。次に、保存場所もコマンドで指定したい場合は、以下の書式を用いる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;defaults write com.apple.screencapture location ~/Pictures/Screenshots&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで使用している &lt;code&gt;~/Pictures/Screenshots&lt;/code&gt; は一例であり、ユーザの環境に合わせて任意のパスに変更することが可能である。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;defaults&lt;/code&gt; コマンドを使用して設定を書き換えただけでは、システムに即座に変更が反映されない場合がある。設定を有効化するためには、macOSのUI管理プロセスである &lt;code&gt;SystemUIServer&lt;/code&gt; を再起動させる必要がある。以下のコマンドを実行することで、Mac本体を再起動させることなく新しい設定を適用できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall SystemUIServer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;コマンドの実行後、実際に &lt;code&gt;Command&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;3&lt;/code&gt; （全画面撮影）や &lt;code&gt;Command&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;4&lt;/code&gt; （範囲指定撮影）を行い、動作を検証する。指定した保存先にファイルが出力されていること、およびファイルの拡張子が &lt;code&gt;.jpg&lt;/code&gt; になっていることを情報ウィンドウ（&lt;code&gt;Command&lt;/code&gt; + &lt;code&gt;I&lt;/code&gt;）で確認する。&lt;/p&gt;&#10;&lt;p&gt;もし設定を元に戻したい場合は、形式を &lt;code&gt;png&lt;/code&gt; に指定し、同様の手順で &lt;code&gt;killall&lt;/code&gt; コマンドを実行すればよい。&lt;/p&gt;&#10;</description></item><item><title>バックアップ戦略 3-2-1ルール</title><link>https://ai.hack-le.com/%F0%9F%93%9D-%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E6%88%A6%E7%95%A5-3-2-1%E3%83%AB%E3%83%BC%E3%83%AB/</link><pubDate>Tue, 16 Dec 2025 16:28:12 +0900</pubDate><guid>https://ai.hack-le.com/%F0%9F%93%9D-%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E6%88%A6%E7%95%A5-3-2-1%E3%83%AB%E3%83%BC%E3%83%AB/</guid><description>&lt;p&gt;3-2-1戦略は、データ保護の冗長性と多様性を確保するための、シンプルかつ非常に効果的な原則である。この戦略は、「3つのコピー」「2種類のメディア」「1つのオフサイトコピー」の3つの数字から構成されており、それぞれの原則が複合的なリスクに対応する役割を担っている。&lt;/p&gt;&#10;&lt;h2 id="3-データのコピーを最低3つ保持する"&gt;3️⃣ データのコピーを最低3つ保持する&#10;&lt;/h2&gt;&lt;p&gt;3-2-1戦略の最初の数字「3」は、&lt;strong&gt;データのコピーを合計3つ保持する&lt;/strong&gt;ことを意味している。この「3つのコピー」とは、元のデータ（プライマリデータ）に加えて、&lt;strong&gt;バックアップされたコピーを2つ&lt;/strong&gt;作成することを指す。&lt;/p&gt;&#10;&lt;p&gt;この冗長性の確保がなぜ重要かというと、バックアップデータそのものが破損するリスクや、何らかの理由で特定のコピーにアクセスできなくなるリスクに対応するためである。例えば、プライマリデータがランサムウェアに暗号化された場合、最初のバックアップコピーもネットワーク経由で同時に暗号化されてしまう可能性がある。しかし、もう一つの独立したコピーが存在していれば、安全にデータを復元できる確率は格段に高くなる。したがって、バックアップの完全な失敗を防ぎ、確実な復旧を実現するためには、最低でも2つのバックアップコピー、つまり合計3つのデータの存在が必要不可欠である。&lt;/p&gt;&#10;&lt;h2 id="2-2種類の異なるメディア媒体に保存する"&gt;2️⃣ 2種類の異なるメディア（媒体）に保存する&#10;&lt;/h2&gt;&lt;p&gt;次に重要なのが「2」の原則、すなわち&lt;strong&gt;2種類の異なるメディア（媒体）にバックアップデータを保存する&lt;/strong&gt;という指針である。&lt;/p&gt;&#10;&lt;p&gt;例えば、プライマリデータを内蔵HDDに保存している場合、最初のバックアップコピーをNASに、そして2番目のバックアップコピーをクラウドストレージに保存するといった組み合わせが考えられる。これは、特定の種類のメディアに固有の障害、たとえば特定のメーカーのHDDの一斉故障や、コントローラチップの欠陥などによるデータアクセス障害からデータを保護する目的がある。異なる技術に基づくストレージを使用することで、一つの技術的な問題がすべてのデータに影響を及ぼすリスクを排除し、システム全体の復旧能力を担保できるのである。&lt;/p&gt;&#10;&lt;h3 id="再現環境と具体例の提示"&gt;再現環境と具体例の提示&#10;&lt;/h3&gt;&lt;p&gt;この原則をPC環境で再現する具体例として、以下の組み合わせが推奨される。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;データ種別&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;保存場所&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;メディアの種類&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;プライマリデータ (1/3)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ユーザーのローカルPC&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;内蔵NVMe SSD&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;バックアップコピー 1 (2/3)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;外部ストレージ&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;USB接続のHDDまたはNAS&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;バックアップコピー 2 (3/3)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;クラウドサービス&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Amazon S3 または Google Drive&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;この例では、内蔵SSDという高速メディア、外部HDD/NASというローカル接続メディア、そしてクラウドというインターネット経由メディアの3種類が利用されており、&lt;strong&gt;SSD（フラッシュメモリ）とHDD（磁気ディスク）&lt;/strong&gt; 、&lt;strong&gt;クラウドストレージ&lt;/strong&gt;という異なる種類のメディアにデータが分散されている。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="1-そのうち1つはオフサイト遠隔地に保管する"&gt;1️⃣ そのうち1つはオフサイト（遠隔地）に保管する&#10;&lt;/h2&gt;&lt;p&gt;最後の原則である「1」は、&lt;strong&gt;バックアップコピーのうち少なくとも1つをオフサイト（遠隔地）に保管する&lt;/strong&gt;ことを強く求めている。オフサイトとは、元のデータや他のバックアップが保存されている場所とは物理的に離れた地理的に安全な場所のことである。&lt;/p&gt;&#10;&lt;p&gt;このオフサイト保管の目的は、&lt;strong&gt;局所的な大規模災害&lt;/strong&gt;、具体的には火災、洪水、地震、あるいは施設全体を標的とした盗難などの、単一の場所で発生する事象からデータを守ることである。オンサイト（同じ場所）にすべてのデータが存在する場合、火災によって建物が焼失すれば、プライマリデータもすべてのバックアップも同時に失われてしまう。しかし、1つのコピーが遠隔地にあれば、主要な施設が完全に機能停止しても、データは安全に保護され、事業の継続（BCP: Business Continuity Plan）を可能とする。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;3-2-1戦略は、データの&lt;strong&gt;冗長性&lt;/strong&gt;、&lt;strong&gt;多様性&lt;/strong&gt;、そして&lt;strong&gt;地理的分散&lt;/strong&gt;という3つの要素を組み合わせることで、データ損失のリスクを最小限に抑えることを可能にする。この戦略の徹底は、データ保護を真に機能させるための基本であり、システム設計における最優先事項として扱うべきである。&lt;/p&gt;&#10;</description></item><item><title>Webブラウザでシェルにアクセスする Shell In A Box のセットアップ備忘録</title><link>https://ai.hack-le.com/web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E3%82%B7%E3%82%A7%E3%83%AB%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B-shell-in-a-box-%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2/</link><pubDate>Mon, 15 Dec 2025 12:34:40 +0900</pubDate><guid>https://ai.hack-le.com/web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E3%82%B7%E3%82%A7%E3%83%AB%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B-shell-in-a-box-%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2/</guid><description>&lt;h2 id="目的と再現環境"&gt;目的と再現環境&#10;&lt;/h2&gt;&lt;p&gt;Webブラウザを経由してサーバーまたはローカルマシンにセキュアにアクセスできるターミナル環境を構築することは、リモートワークフローや簡易的なサーバー管理において利便性が高い。本記事は、WebベースのSSHクライアントである Shell In A Box (SIA) をmacOS上にセルフホストし、LAN内の他のPCからアクセス可能にするまでの具体的な手順を記録することを目的とする。&lt;/p&gt;&#10;&lt;h3 id="前提となる再現環境"&gt;前提となる再現環境&#10;&lt;/h3&gt;&lt;p&gt;本記事で解説する手順は、以下の環境を前提とし、Macをホストマシンとして使用する。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ホストOS&lt;/strong&gt;: macOS (Homebrewがインストールされていること)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;クライアント環境&lt;/strong&gt;: LAN内の任意のPCにインストールされたWebブラウザ&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ツール&lt;/strong&gt;: Shell In A Box (SIA)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;この手順は、特別な外部サービスを必要とせず、Homebrewが利用できる環境であればすぐに再現できる。&lt;/p&gt;&#10;&lt;h2 id="shell-in-a-boxのインストールと基本的な起動"&gt;Shell In A Boxのインストールと基本的な起動&#10;&lt;/h2&gt;&lt;p&gt;Shell In A Box を使用可能にする最初のステップは、MacのパッケージマネージャーであるHomebrewを利用したツールのインストールである。HomebrewはmacOS上でUNIXツールやパッケージを簡単に管理するためのデファクトスタンダードであり、この手順を大幅に簡略化する。&lt;/p&gt;&#10;&lt;p&gt;Homebrewが導入されていることを確認した後、ターミナルで以下のコマンドを実行し、Shell In A Boxをインストールする。&lt;/p&gt;&#10;&lt;p&gt;Bash&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install shellinabox&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;インストール完了後、Shell In A Box デーモン（&lt;code&gt;shellinaboxd&lt;/code&gt;）を起動する。LAN内での利用を想定する場合、アクセス制御とセキュリティのため、簡易テスト用の &lt;code&gt;-t&lt;/code&gt; オプションではなく、ログインプロンプトを表示するデフォルトモードで起動することが推奨される。&lt;/p&gt;&#10;&lt;p&gt;Bash&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;shellinaboxd&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを実行すると、Shell In A BoxはデフォルトでTCPポート &lt;code&gt;4200&lt;/code&gt; を使用して接続待ちの状態となる。この際、ターミナルには特にメッセージが表示されないことが多い。この状態でMac上のWebブラウザ（例: Chrome, Safari）を開き、&lt;code&gt;http://localhost:4200/&lt;/code&gt; にアクセスすることで、ログインプロンプトが表示されることを確認できる。ログイン認証には、ホストマシン（Mac）の&lt;strong&gt;ユーザー名とパスワード&lt;/strong&gt;を使用する。これにより、ブラウザ内でMacのターミナルを操作する準備が整う。この基本的な起動により、ローカルマシンでの動作が確認でき、次のステップであるLAN内アクセスへの布石となる。&lt;/p&gt;&#10;&lt;h2 id="lan内アクセスを可能にする設定と手順"&gt;LAN内アクセスを可能にする設定と手順&#10;&lt;/h2&gt;&lt;p&gt;Shell In A Boxは、デフォルトでMacのすべてのネットワークインターフェースからの接続を待ち受ける設定になっている。そのため、LAN内の他のPCからアクセスを可能にするために必要なのは、ホストであるMacのローカルIPアドレスを確認することのみである。これにより、MacのWebブラウザだけでなく、ネットワークを介した任意のデバイスからシェルにアクセスすることが可能となる。&lt;/p&gt;&#10;&lt;p&gt;まず、Shell In A BoxにアクセスするためのホストとなるMacのプライベートIPアドレスを確認する。これは「システム設定」や「システム環境設定」の「ネットワーク」セクションから確認可能である。例えば、IPアドレスが &lt;code&gt;192.168.1.10&lt;/code&gt; であると仮定する。このIPアドレスは、LAN内でのみ有効なアドレスであり、外部インターネットからのアクセスには使用されない。&lt;/p&gt;&#10;&lt;p&gt;次に、LAN内の他のPCのWebブラウザを開き、以下の形式のURLを入力してアクセスする。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://&lt;span class="o"&gt;[&lt;/span&gt;MacのIPアドレス&lt;span class="o"&gt;]&lt;/span&gt;:4200/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体例として、IPアドレスが &lt;code&gt;192.168.1.10&lt;/code&gt; の場合、アクセスURLは &lt;code&gt;http://192.168.1.10:4200/&lt;/code&gt; となる。このURLにアクセスすると、ブラウザにShell In A Boxのログイン画面が表示される。ここで、ホストMacのユーザー名とパスワードを入力することで、LAN内の任意のPCからMacのシェル環境を操作することが可能となる。この方法は、Webベースのサービスとしてシェルを提供するため、クライアント側に追加のSSHクライアントソフトウェアをインストールする必要がないという利点がある。このプロセス全体を通じて、セキュリティを確保するため、&lt;strong&gt;パスワード認証&lt;/strong&gt;が必須となることに留意すべきである。&lt;/p&gt;&#10;&lt;h2 id="pc起動時の自動起動設定"&gt;PC起動時の自動起動設定&#10;&lt;/h2&gt;&lt;p&gt;Shell In A Boxの利便性を最大化するには、ホストマシン（Mac）の起動時に自動的にサービスを開始させることが重要である。macOSでは、ユーザーログイン後にサービスを自動起動させるために、標準機能である &lt;code&gt;launchd&lt;/code&gt; とその設定ファイル（&lt;code&gt;.plist&lt;/code&gt; ファイル）を利用する。これにより、手動で毎回ターミナルで起動コマンドを実行する手間を省くことができる。&lt;/p&gt;&#10;&lt;p&gt;まず、以下の構造を持つプロパティリスト（&lt;code&gt;plist&lt;/code&gt;）ファイルをホームディレクトリ内の適切な場所に作成する。ファイル名は慣例に従い、&lt;code&gt;com.shellinabox.server.plist&lt;/code&gt; とする。保存場所はユーザーごとのサービス定義を格納するディレクトリである &lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt; である。&lt;/p&gt;&#10;&lt;p&gt;XML&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ~/Library/LaunchAgents/com.shellinabox.server.plist&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;com.shellinabox.server&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/usr/local/bin/shellinaboxd&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;/array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;true/&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;KeepAlive&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;true/&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;UserName&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;（Macのユーザー名）&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;StandardErrorPath&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/tmp/shellinabox.err&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;StandardOutPath&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/tmp/shellinabox.out&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意点として&lt;/strong&gt;、&lt;code&gt;&amp;lt;key&amp;gt;UserName&amp;lt;/key&amp;gt;&lt;/code&gt; の値には、実際にShell In A Boxを実行するMacのユーザー名を正確に記述する必要がある。&lt;/p&gt;&#10;&lt;p&gt;ファイルを作成した後、ターミナルに戻り、&lt;code&gt;launchctl&lt;/code&gt; コマンドを使用してサービスをシステムに登録し、ロード（起動）する。&lt;/p&gt;&#10;&lt;p&gt;Bash&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl load ~/Library/LaunchAgents/com.shellinabox.server.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この操作により、Shell In A Boxのサービスが即座に起動し、かつ、次回以降のMacの再起動時やログイン時に自動的に実行されるようになる。この設定によって、Webブラウザを開くだけで、常にLAN内からMacのシェル環境にアクセスできる状態が維持され、特にWordPress管理CLIの実行などの用途において、シームレスな作業環境が提供されるのである。&lt;/p&gt;&#10;</description></item><item><title>bashでターミナル間の履歴を共有する方法</title><link>https://ai.hack-le.com/bash%E3%81%A7%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E9%96%93%E3%81%AE%E5%B1%A5%E6%AD%B4%E3%82%92%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Thu, 27 Nov 2025 14:50:56 +0900</pubDate><guid>https://ai.hack-le.com/bash%E3%81%A7%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E9%96%93%E3%81%AE%E5%B1%A5%E6%AD%B4%E3%82%92%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;bash の履歴は通常、各ターミナルが独立して管理しており、複数のウィンドウを開いて作業していると、過去に実行したコマンドが別のターミナルに反映されず不便である。この問題は、bash が履歴ファイル（一般に &lt;code&gt;~/.bash_history&lt;/code&gt;）を読み書きするタイミングが限られていることに起因する。&lt;/p&gt;&#10;&lt;p&gt;デフォルトでは、ターミナル終了時に履歴が書き込まれる仕様であり、そのためリアルタイムの共有は行われない。本稿では、この挙動を変更し、&lt;strong&gt;どのターミナルからも最新履歴を利用できる環境を構築する方法&lt;/strong&gt;について解説する。&lt;/p&gt;&#10;&lt;h2 id="履歴共有の仕組み"&gt;履歴共有の仕組み&#10;&lt;/h2&gt;&lt;p&gt;bash に対して「履歴をリアルタイムに書き込み、かつ常に読み込む」ことを明示的に指示する。bash には &lt;code&gt;PROMPT_COMMAND&lt;/code&gt; という特別な環境変数が存在し、これはプロンプトが表示される直前に bash が必ず実行するコマンド列を定義する。&lt;/p&gt;&#10;&lt;p&gt;履歴同期のためには、この仕組みを利用して、直前のコマンドを履歴ファイルに追記する &lt;code&gt;history -a&lt;/code&gt; を実行し、他ターミナルが書き込んだ履歴を読み込む &lt;code&gt;history -n&lt;/code&gt; を実行するという二段構えが必要になる。また、履歴ファイルの内容を上書きせず追記する &lt;code&gt;histappend&lt;/code&gt; を有効にすることで、複数ターミナルが同時に履歴を書いても衝突が起こらない。&lt;/p&gt;&#10;&lt;h2 id="実装方法"&gt;実装方法&#10;&lt;/h2&gt;&lt;p&gt;履歴共有の設定は &lt;code&gt;.bashrc&lt;/code&gt; に記述することで有効になる。&lt;code&gt;.bashrc&lt;/code&gt; はログインシェルでなくとも読み込まれるため、複数ターミナルで開く通常の対話型シェルの設定として適切である。以下に示す設定を追記すれば、ターミナルを跨いで履歴が共有される。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt; -s histappend&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PROMPT_COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;history -a; history -n&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定を追加したら、&lt;code&gt;source ~/.bashrc&lt;/code&gt; を実行して反映させる。&lt;/p&gt;&#10;&lt;h2 id="強制同期が必要な場合オプション"&gt;強制同期が必要な場合（オプション）&#10;&lt;/h2&gt;&lt;p&gt;履歴の衝突や順序の乱れが気になるような環境では、より強制的な同期方法として &lt;code&gt;history -c&lt;/code&gt; を併用する設定がある。これは一度メモリ上の履歴を全消去し、その後ファイルから再度読み込むため、最新状態が常に正確に再現される。設定は以下のとおりである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PROMPT_COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;history -a; history -c; history -n&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ただし、この手法は履歴の並びが不自然になりやすいなどの副作用があるため、常用するというよりは、履歴を厳密に同期させたい特定の場面でのみ利用すべきである。&lt;/p&gt;&#10;</description></item><item><title>Debian 系 Linux で Dropbox をアンインストールする手順の備忘録</title><link>https://ai.hack-le.com/debian-%E7%B3%BB-linux-%E3%81%A7-dropbox-%E3%82%92%E3%82%A2%E3%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%89%8B%E9%A0%86%E3%81%AE%E5%82%99%E5%BF%98%E9%8C%B2/</link><pubDate>Sat, 22 Nov 2025 03:36:39 +0900</pubDate><guid>https://ai.hack-le.com/debian-%E7%B3%BB-linux-%E3%81%A7-dropbox-%E3%82%92%E3%82%A2%E3%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%89%8B%E9%A0%86%E3%81%AE%E5%82%99%E5%BF%98%E9%8C%B2/</guid><description>&lt;h2 id="本記事の前提と目的"&gt;本記事の前提と目的&#10;&lt;/h2&gt;&lt;p&gt;Debian 系 Linux 環境に Dropbox を導入したあと、使用用途がなくなり削除したい状況は珍しくない。とくに Linux 版 Dropbox は GUI パッケージと自動ダウンロードされたユーザーディレクトリ側の実体が混在しており、どのファイルを消せば完全に片付くのか迷いやすい。本記事では、apt パッケージとしての Dropbox と &lt;code&gt;~/.dropbox-dist&lt;/code&gt; に展開された実体の両方を整理し、確実にアンインストールする方法を記録する。対象環境は以下である。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Debian / Ubuntu / Linux Mint などの APT 系ディストリビューション&lt;/li&gt;&#10;&lt;li&gt;ターミナル操作を前提とする&lt;/li&gt;&#10;&lt;li&gt;Dropbox のインストール方法を特定しきれなくても対応可能な手順を採用する&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;環境差異によって Dropbox の配置が異なることはあるが、この記事の内容を踏めばユーザーレベルでもシステムレベルでも残存ファイルを整理できるようにしてある。&lt;/p&gt;&#10;&lt;h2 id="プロセスを停止してアンインストールの下準備をする"&gt;プロセスを停止してアンインストールの下準備をする&#10;&lt;/h2&gt;&lt;p&gt;Dropbox を削除するとき、まず実行中のプロセスを止める必要がある。ソフトウェアのアンインストールは、走行中の列車を安全に空駅へ入れる行為のようなものだ。動いたままではどんな手順も正しく作用しない。&lt;/p&gt;&#10;&lt;p&gt;実際の操作は極めて単純で、Dropbox が提供する CLI を使う。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dropbox stop&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この段階でプロセスが完全に停止し、ディレクトリ削除やパッケージ削除が安全に進められる。もし &lt;code&gt;dropbox&lt;/code&gt; コマンドが見つからない場合でも問題はなく、プロセスが存在しないかすでに停止している状態であるため、このまま次へ進める。&lt;/p&gt;&#10;&lt;h2 id="apt-パッケージとしての-dropbox-を削除する"&gt;APT パッケージとしての Dropbox を削除する&#10;&lt;/h2&gt;&lt;p&gt;Debian 系 Linux におけるソフトウェア削除の中心はパッケージ管理である。他の方法でインストールした場合も想定されるが、まずは APT 管理下に Dropbox が存在するかどうか確実に確認して削除することが重要である。&lt;/p&gt;&#10;&lt;p&gt;APT 経由でインストールされている場合は次のコマンドで完全削除できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt purge dropbox&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt autoremove&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;purge&lt;/code&gt; を使う理由は設定ファイルごと削除するためであり、復元の必要がない今回の用途では最も合理的である。そして &lt;code&gt;autoremove&lt;/code&gt; によって Dropbox が依存していたパッケージが不要であれば自動的に取り除かれ、環境がよりクリーンになる。&lt;/p&gt;&#10;&lt;p&gt;もし &lt;code&gt;dropbox&lt;/code&gt; パッケージが存在しない場合はエラーが返るが、その場合はパッケージ管理下に Dropbox がないだけなので、そのまま次の手順に進めばよい。エラーは無視して構わない。&lt;/p&gt;&#10;&lt;h2 id="dropbox-dist-と設定ディレクトリを削除して実体を片付ける"&gt;&lt;code&gt;~/.dropbox-dist&lt;/code&gt; と設定ディレクトリを削除して実体を片付ける&#10;&lt;/h2&gt;&lt;p&gt;Linux 版 Dropbox のもっとも特徴的な点は、実体がユーザーディレクトリ配下に自動ダウンロードされることにある。これが削除漏れを引き起こす最大の理由である。APT パッケージを削除しても、実際のバイナリは &lt;code&gt;~/.dropbox-dist&lt;/code&gt; に残り続け、ひっそりとスペースを占拠し続ける。&lt;/p&gt;&#10;&lt;p&gt;不要になった Dropbox の本体を削除するには以下を実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf ~/.dropbox-dist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf ~/.dropbox&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;~/.dropbox-dist&lt;/code&gt; は Dropbox の実行ファイル群、&lt;code&gt;~/.dropbox&lt;/code&gt; は設定ファイルの集合である。これらを削除することで、実体と環境設定の両方が完全に取り除かれる。Linux デスクトップ環境の「影の居候」が消える瞬間である。&lt;/p&gt;&#10;&lt;h2 id="古い環境で残る可能性のある自動起動スクリプトの整理"&gt;古い環境で残る可能性のある自動起動スクリプトの整理&#10;&lt;/h2&gt;&lt;p&gt;Dropbox はかつて init スクリプトや自動起動用のファイルを配置していた時期があり、古い環境では &lt;code&gt;/etc/init.d/dropbox&lt;/code&gt; が残っているケースがある。この存在はまるで役目を終えたトランジスターラジオが棚の奥に置かれ続けるようなもので、害はないが散らかりの原因となる。&lt;/p&gt;&#10;&lt;p&gt;削除は次の一行で足りる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -f /etc/init.d/dropbox&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ファイルが存在しない場合でも &lt;code&gt;-f&lt;/code&gt; オプションのおかげでエラーなく処理が完了する。これにより残存する可能性のあるシステムレベルの起動設定も片付き、Dropbox 関連の痕跡はすべて削除される。&lt;/p&gt;&#10;&lt;h2 id="出典"&gt;出典&#10;&lt;/h2&gt;&lt;p&gt;Debian 系 Linux における Dropbox のパッケージ情報やユーザーディレクトリ構造については、以下を参照した。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Dropbox Help Center – Install on Linux &lt;a class="link" href="https://help.dropbox.com/installs/linux-install" target="_blank" rel="noopener"&#10; &gt;https://help.dropbox.com/installs/linux-install&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Dropbox コマンドラインインターフェイス &lt;a class="link" href="https://help.dropbox.com/ja-jp/installs/modern-linux" target="_blank" rel="noopener"&#10; &gt;https://help.dropbox.com/ja-jp/installs/modern-linux&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>AutoHotkey v2 を初めて使う場合の導入から基本的なスクリプト作成まで</title><link>https://ai.hack-le.com/autohotkey-v2-%E3%82%92%E5%88%9D%E3%82%81%E3%81%A6%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88%E3%81%AE%E5%B0%8E%E5%85%A5%E3%81%8B%E3%82%89%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E3%82%B9%E3%82%AF%E3%83%AA/</link><pubDate>Fri, 14 Nov 2025 02:36:58 +0900</pubDate><guid>https://ai.hack-le.com/autohotkey-v2-%E3%82%92%E5%88%9D%E3%82%81%E3%81%A6%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88%E3%81%AE%E5%B0%8E%E5%85%A5%E3%81%8B%E3%82%89%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E3%82%B9%E3%82%AF%E3%83%AA/</guid><description>&lt;h2 id="インストール"&gt;インストール&#10;&lt;/h2&gt;&lt;p&gt;AutoHotkey v2 は公式サイトから入手できます。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://www.autohotkey.com/" target="_blank" rel="noopener"&#10; &gt;AutoHotkey&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;exeファイルを実行すると、インストールが開始されます。&lt;/p&gt;&#10;&lt;p&gt;最初のスクリプトを作るには、任意のフォルダを開き、空いている場所で右クリックし、新規作成から AutoHotkey Script を選びます。これにより &lt;code&gt;.ahk&lt;/code&gt; ファイルが生成されるので、ファイル名をわかりやすいものに変更し、右クリックから編集を選んでテキストエディタで開きます。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;.ahk&lt;/code&gt;ファイルをダブルクリックして実行することができます。&lt;/p&gt;&#10;&lt;h2 id="バージョンの注意"&gt;バージョンの注意&#10;&lt;/h2&gt;&lt;p&gt;AutoHotkey v2 では旧来と書式が異なっているため、注意が必要です。スクリプトの先頭に &lt;code&gt;#Requires AutoHotkey v2.0&lt;/code&gt; を書いておくとバージョンの混在を防げます。&lt;/p&gt;&#10;&lt;p&gt;公式ドキュメントの構文はこうなっています。(&lt;a class="link" href="https://ahkscript.github.io/ja/docs/v2/lib/WinMove.htm?utm_source=chatgpt.com" target="_blank" rel="noopener"&#10; &gt;AHKScript&lt;/a&gt;)&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WinMove X, Y, Width, Height, WinTitle, WinText, ExcludeTitle, ExcludeText&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;X, Y, Width, Height&lt;/code&gt; … 数値&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WinTitle&lt;/code&gt; など … 文字列（ウィンドウタイトルや &lt;code&gt;ahk_exe notepad.exe&lt;/code&gt; など）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;ここにカッコを付けてはいけません。&lt;/strong&gt;&lt;br&gt;&#10;&lt;code&gt;WinMove(&amp;quot;メモ帳&amp;quot;, 100, 100, 800, 600)&lt;/code&gt; と書くと、それは「WinMove 関数」を呼び出す形になり、&lt;br&gt;&#10;第1引数に本来「数値（X 座標）」を渡すべきところに「メモ帳」という文字列を渡しているので、&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;Parameter #1 of WinMove requires a Number, but received a String.&#10;Specifically: メモ帳&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;というエラーが出ます。&lt;/p&gt;&#10;&lt;h2 id="そのままコピペして試せるサンプル"&gt;そのままコピペして試せるサンプル&#10;&lt;/h2&gt;&lt;p&gt;動作確認しやすいサンプルをまとめます。&lt;/p&gt;&#10;&lt;h3 id="サンプル1メモ帳を起動して左上に移動"&gt;サンプル1：メモ帳を起動して左上に移動&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#Requires AutoHotkey v2.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Run &lt;span class="s2"&gt;&amp;#34;notepad.exe&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WinWait &lt;span class="s2"&gt;&amp;#34;ahk_exe notepad.exe&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WinMove 100, 100, 800, &lt;span class="m"&gt;600&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ExitApp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="サンプル2既に開いているメモ帳を移動"&gt;サンプル2：既に開いているメモ帳を移動&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#Requires AutoHotkey v2.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WinMove 100, 100, 800, 600, &lt;span class="s2"&gt;&amp;#34;ahk_exe notepad.exe&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ExitApp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="サンプル3アクティブウィンドウをホットキーで移動"&gt;サンプル3：アクティブウィンドウをホットキーで移動&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#Requires AutoHotkey v2.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#n::&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; WinMove 100, 100, 800, 600, &lt;span class="s2"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この形に直せば、エラーなく動作するはずです。AutoHotkey v2 の WinMove は「関数ではなくコマンドとして使う」という一点を押さえると、あとは座標とタイトルを変えるだけで応用できます。&lt;/p&gt;&#10;</description></item><item><title>壊れる正しさ：DKIMが突きつけた近代メール運用の矛盾</title><link>https://ai.hack-le.com/%E5%A3%8A%E3%82%8C%E3%82%8B%E6%AD%A3%E3%81%97%E3%81%95%EF%BC%9Adkim%E3%81%8C%E7%AA%81%E3%81%8D%E3%81%A4%E3%81%91%E3%81%9F%E8%BF%91%E4%BB%A3%E3%83%A1%E3%83%BC%E3%83%AB%E9%81%8B%E7%94%A8%E3%81%AE/</link><pubDate>Thu, 13 Nov 2025 00:16:58 +0900</pubDate><guid>https://ai.hack-le.com/%E5%A3%8A%E3%82%8C%E3%82%8B%E6%AD%A3%E3%81%97%E3%81%95%EF%BC%9Adkim%E3%81%8C%E7%AA%81%E3%81%8D%E3%81%A4%E3%81%91%E3%81%9F%E8%BF%91%E4%BB%A3%E3%83%A1%E3%83%BC%E3%83%AB%E9%81%8B%E7%94%A8%E3%81%AE/</guid><description>&lt;p&gt;セキュリティは正しさを求め、運用は寛容を求める。&lt;br&gt;&#10;この二つの願いが交わる点に、2025年のメールサーバー障害はあった。&lt;/p&gt;&#10;&lt;p&gt;ある事業者が「DKIMポリシー強化」を実施した。&lt;br&gt;&#10;だが、その厳格な設定は結果として、多くの正当なメールを拒み、通信の血流を止めた。&lt;br&gt;&#10;19分間の緊急メンテナンスの末、設定は元に戻され、安定が回復したという。&lt;br&gt;&#10;この短い事件に、現代のネットワーク社会の病理が凝縮されている。&lt;/p&gt;&#10;&lt;p&gt;DKIMとは、送信時にメール本文とヘッダの一部を署名し、改ざんを検知する仕組みである。&lt;br&gt;&#10;署名が正しければ「pass」、異なれば「fail」。&lt;br&gt;&#10;単純な仕組みに見えるが、そこに潜むのは“正しすぎる世界”の脆さだ。&lt;/p&gt;&#10;&lt;p&gt;メールという古代の遺跡のような通信方式は、いまや数え切れぬ中継サーバー、&lt;br&gt;&#10;セキュリティゲートウェイ、メーリングリスト、クラウドスキャン装置を経由して届けられる。&lt;br&gt;&#10;途中で一文字でも改行位置が変われば、署名は壊れる。&lt;br&gt;&#10;フッターを一行追加しただけで、正当な通信が「改ざん」と断定される。&lt;br&gt;&#10;DKIMは数学的には正しい。しかし、&lt;strong&gt;社会的には不寛容である&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;このとき必要になるのがDMARCだ。&lt;br&gt;&#10;DKIMやSPFの結果を統合し、どの程度の“失敗”を許容するかを定義する。&lt;br&gt;&#10;none、quarantine、reject──それはまるで、&lt;br&gt;&#10;「信頼する／様子を見る／断罪する」という人間社会の倫理判断の縮図である。&lt;br&gt;&#10;だが今回の事故では、その調停役が置き去りにされていた。&lt;br&gt;&#10;セキュリティが倫理を追い越し、可用性を焼き尽くしたのである。&lt;/p&gt;&#10;&lt;p&gt;厳密であることは、しばしば美徳とされる。&lt;br&gt;&#10;だがネットワークの現場では、厳密さが壊すのは敵ではなく、味方だ。&lt;br&gt;&#10;数学的な整合性を突き詰めたシステムほど、現実の曖昧さに耐えられなくなる。&lt;br&gt;&#10;署名の一致に人生を賭けたDKIMは、&lt;br&gt;&#10;人間社会の「まあいいか」という文化を、完全に理解できない。&lt;/p&gt;&#10;&lt;p&gt;そして、これこそが現代の技術者が抱える根源的な矛盾だ。&lt;br&gt;&#10;私たちは正確さの宗教に生きながら、現実というノイズを運用しなければならない。&lt;br&gt;&#10;完璧な検証が、通信を止める。&lt;br&gt;&#10;安全を守ろうとした手が、信頼を壊す。&lt;br&gt;&#10;技術はいつも、己の正しさに踏み抜かれる。&lt;/p&gt;&#10;&lt;p&gt;それでも私たちは、また新しい設定を試みる。&lt;br&gt;&#10;ロールバックを繰り返しながら、妥協と理想の狭間を調整する。&lt;br&gt;&#10;メールという老朽化した制度の上に、現代の矛盾を積み重ねながら。&lt;/p&gt;&#10;</description></item><item><title>Windows + MSYS2/MinGW + Vulkan で whisper.cpp を使う</title><link>https://ai.hack-le.com/windows-msys2-mingw-vulkan-%E3%81%A7-whisper-cpp-%E3%82%92%E4%BD%BF%E3%81%86/</link><pubDate>Wed, 05 Nov 2025 14:03:42 +0900</pubDate><guid>https://ai.hack-le.com/windows-msys2-mingw-vulkan-%E3%81%A7-whisper-cpp-%E3%82%92%E4%BD%BF%E3%81%86/</guid><description>&lt;ul&gt;&#10;&lt;li&gt;Windows 11&lt;/li&gt;&#10;&lt;li&gt;GPU: Vulkan 対応 (NVIDIA / AMD / Intel Arc いずれも可)&lt;/li&gt;&#10;&lt;li&gt;MSYS2 / MinGW64 シェルを使用&lt;/li&gt;&#10;&lt;li&gt;Vulkan SDK をインストール済み &lt;a class="link" href="https://vulkan.lunarg.com/sdk/home" target="_blank" rel="noopener"&#10; &gt;https://vulkan.lunarg.com/sdk/home&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;MSYS2 のインストールと更新は省略するが、&lt;code&gt;pacman -Syu&lt;/code&gt; による更新は済ませておく。&lt;/p&gt;&#10;&lt;p&gt;MinGW64 シェルで以下を実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S --needed base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake git&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;cloneする。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/ggml-org/whisper.cpp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd whisper.cpp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MinGW64 シェルで次を実行する。Vulkan を使う場合は &lt;code&gt;-DGGML_VULKAN=1&lt;/code&gt; を指定する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cmake -B build -G &amp;#34;MinGW Makefiles&amp;#34; -DGGML_VULKAN=1 -DCMAKE_BUILD_TYPE=Release&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mingw32-make -C build -j8&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ビルドが成功すると、&lt;code&gt;build/bin/&lt;/code&gt; 内に実行ファイルが生成される。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;build/bin/whisper-cli.exe&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;モデルは公式から取得する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./models/download-ggml-model.sh large-v3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;文字起こしの実行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./build/bin/whisper-cli.exe \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m models/ggml-large-v3.bin \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -f samples/jfk.wav \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output-txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Vulkan が有効な場合は、初期化ログに Vulkan バックエンドが表示される。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;whisper_backend_init_gpu: using Vulkan backend&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上。&lt;/p&gt;&#10;</description></item><item><title>動画ダウンロードの定番──yt-dlpという万能ツール</title><link>https://ai.hack-le.com/%E5%8B%95%E7%94%BB%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%AE%E5%AE%9A%E7%95%AA%E2%94%80%E2%94%80yt-dlp%E3%81%A8%E3%81%84%E3%81%86%E4%B8%87%E8%83%BD%E3%83%84%E3%83%BC%E3%83%AB/</link><pubDate>Wed, 05 Nov 2025 08:11:15 +0900</pubDate><guid>https://ai.hack-le.com/%E5%8B%95%E7%94%BB%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%AE%E5%AE%9A%E7%95%AA%E2%94%80%E2%94%80yt-dlp%E3%81%A8%E3%81%84%E3%81%86%E4%B8%87%E8%83%BD%E3%83%84%E3%83%BC%E3%83%AB/</guid><description>&lt;p&gt;動画サイトの海を自由に泳ぎたい者にとって、&lt;code&gt;yt-dlp&lt;/code&gt;は最強の羅針盤である。YouTubeをはじめ、無数の配信サイトから動画や音声を自在に取得できるその力は、まるで多言語を理解する通訳のように万能だ。だが、いくら名ツールでも、その使い方を知らなければただの宝の持ち腐れである。本稿では、&lt;code&gt;yt-dlp&lt;/code&gt;の基本的な操作法を一通り押さえ、使いこなすための筋道を記す。&lt;/p&gt;&#10;&lt;h2 id="導入という第一歩"&gt;導入という第一歩&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;yt-dlp&lt;/code&gt;はPython製のツールであり、インストールも簡潔だ。ターミナルで次の一行を叩くだけで始まる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この瞬間、あなたのマシンに強力なダウンローダーが宿る。macOSやLinuxを使っているなら、Homebrew経由での導入も選べる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;brew&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更新も容易であり、常に最新版を保つことが推奨される。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;コマンドラインに抵抗を覚える者もいるが、一度慣れればGUIのような視覚的ツールよりもはるかに迅速で正確だ。&lt;/p&gt;&#10;&lt;h2 id="基本動作urlひとつで完結する魔法"&gt;基本動作──URLひとつで完結する魔法&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;yt-dlp&lt;/code&gt;の核心はシンプルな命令にある。対象となる動画URLを指定すれば、それだけでダウンロードが始まる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXXXXXXXX&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;特別なオプションを付けなくとも、自動で最高画質を選択して保存してくれる。まるでソムリエが最適なワインを差し出すように、ユーザーの手を煩わせない。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="音だけを抜き出すという美学"&gt;音だけを抜き出すという美学&#10;&lt;/h2&gt;&lt;p&gt;動画のすべてを欲する必要はない。ときに音声だけで十分なこともある。音楽、講演、ラジオ──それらを純粋な音として残したいなら、次のコマンドが適切だ。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--audio-format mp3 https://www.youtube.com/watch?v=XXXXXXXXXXX&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-x&lt;/code&gt;は音声抽出を意味し、&lt;code&gt;--audio-format&lt;/code&gt;で形式を指定できる。&lt;code&gt;mp3&lt;/code&gt;のほか、&lt;code&gt;m4a&lt;/code&gt;や&lt;code&gt;wav&lt;/code&gt;なども選択可能だ。映像を削ぎ落とし、声や音だけを抽出する行為には、ある種の潔さがある。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="整理整頓という技術"&gt;整理整頓という技術&#10;&lt;/h2&gt;&lt;p&gt;複数の動画を扱うとき、ファイル名の管理は混沌に陥りがちだ。そこで役立つのが出力指定オプションである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%(title)s.%(ext)s&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXXXXXXXX&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;%(title)s&lt;/code&gt;は動画タイトル、&lt;code&gt;%(ext)s&lt;/code&gt;は拡張子を示す。保存先フォルダを指定したければ、パスを追加することもできる。この設定ひとつで、ライブラリ全体が整然と並ぶ。細部へのこだわりが、長期的な快適さを生むのだ。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="フォーマットを選ぶ自由"&gt;フォーマットを選ぶ自由&#10;&lt;/h2&gt;&lt;p&gt;映像のフォーマットや画質を厳密に選びたい場面もある。そのときは、まず利用可能な形式を一覧で確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXXXXXXXX&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一覧には画質、コーデック、サイズなどの情報が並ぶ。そこから望むフォーマットIDを指定して実行すればよい。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXXXXXXXX&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;コマンドひとつで、容量を抑えたい場合も、高画質を追求したい場合も自在に選べる。この自由度こそが&lt;code&gt;yt-dlp&lt;/code&gt;の真髄である。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="プレイリストを一括で手に入れる"&gt;プレイリストを一括で手に入れる&#10;&lt;/h2&gt;&lt;p&gt;YouTubeのプレイリストURLを指定すれば、連続した動画をまとめてダウンロードできる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dlp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXXXXXXXX&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;講義シリーズやミュージックアルバムのような連番構成の動画には特に有効だ。時間を節約し、統一感ある保存が叶う。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="結語コマンドラインに宿る洗練"&gt;結語──コマンドラインに宿る洗練&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;yt-dlp&lt;/code&gt;の魅力は、単なる便利さを超えている。短い命令の中に、精密な制御と柔軟な設計が共存しているからだ。クリック操作では到達できないレベルの自由がここにある。コマンドラインは不器用な人のための道具ではなく、考える者のための筆記具である。&lt;/p&gt;&#10;&lt;p&gt;動画をダウンロードするという単純な行為の背後には、情報をどう扱い、どう保存するかという哲学が潜んでいる。その第一歩として、&lt;code&gt;yt-dlp&lt;/code&gt;を知ることは、デジタル時代のリテラシーの一端を手にすることに等しい。&lt;/p&gt;&#10;</description></item><item><title>Windows 11で右クリックメニューを旧スタイルに戻す方法（レジストリ設定）</title><link>https://ai.hack-le.com/windows-11%E3%81%A7%E5%8F%B3%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%92%E6%97%A7%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E6%88%BB%E3%81%99%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 27 Oct 2025 20:07:47 +0900</pubDate><guid>https://ai.hack-le.com/windows-11%E3%81%A7%E5%8F%B3%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%92%E6%97%A7%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E6%88%BB%E3%81%99%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;Windows 11では、エクスプローラ上で右クリックしたときに表示されるコンテキストメニューが、簡略化された新しい形式に変更された。従来のメニューに慣れているユーザーにとっては、毎回「Shift＋右クリック」を押さないと従来のフルメニューが出ない仕様は煩雑である。本稿では、この挙動をレジストリ設定によって変更し、通常の右クリック操作だけで旧来のメニューを表示させる方法を記録する。&lt;/p&gt;&#10;&lt;h2 id="前提環境"&gt;前提環境&#10;&lt;/h2&gt;&lt;p&gt;本手順は &lt;strong&gt;Windows 11 （21H2以降）&lt;/strong&gt; を対象とする。レジストリの編集には管理者権限が必要であり、誤った操作はシステムに影響を与えるおそれがある。編集前に必ずレジストリ全体のバックアップを取得しておくことを推奨する。&lt;/p&gt;&#10;&lt;h2 id="設定手順"&gt;設定手順&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;「Win＋R」キーを押し、&lt;code&gt;regedit&lt;/code&gt; と入力してレジストリエディタを起動する。&lt;/li&gt;&#10;&lt;li&gt;次のキーに移動する。 &lt;code&gt;HKEY_CURRENT_USER\Software\Classes\CLSID&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;CLSID&lt;/code&gt; の上で右クリックし、「新規」→「キー」を選択して、以下の名前で作成する。 &lt;code&gt;{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;さらにその下に「InprocServer32」というキーを新規作成する。 &lt;code&gt;HKEY_CURRENT_USER\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;「InprocServer32」を選択した状態で、右側の「(既定)」をダブルクリックし、値データを空欄のまま「OK」を押す。&lt;/li&gt;&#10;&lt;li&gt;レジストリエディタを閉じ、PCを再起動する。もしくは以下のコマンドでエクスプローラを再起動してもよい。 &lt;code&gt;taskkill /f /im explorer.exe start explorer.exe&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;以上の操作で、通常の右クリックのみで従来のフルコンテキストメニューが表示されるようになる。&lt;/p&gt;&#10;&lt;h2 id="元に戻す方法"&gt;元に戻す方法&#10;&lt;/h2&gt;&lt;p&gt;変更を元に戻したい場合は、作成したキーを削除すればよい。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HKEY_CURRENT_USER\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;削除後に再起動すると、Windows 11の新しい簡略メニューに戻る。&lt;/p&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;p&gt;この設定はMicrosoftの公式サポート対象外であり、将来のWindows更新によって無効化される可能性がある。特にエクスプローラ関連の仕様変更が入る大型アップデート後は、再度確認が必要である。&lt;/p&gt;&#10;&lt;h2 id="参考資料"&gt;参考資料&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://www.elevenforum.com/t/disable-show-more-options-context-menu-in-windows-11.1589/" target="_blank" rel="noopener"&#10; &gt;ElevenForum: Disable “Show More Options” Context Menu in Windows 11&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://www.lifewire.com/bring-back-old-context-menu-in-windows-11-8603528/" target="_blank" rel="noopener"&#10; &gt;LifeWire: How to Bring Back the Old Right-Click Menu in Windows 11&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://superuser.com/questions/1854126/how-can-i-get-back-old-context-menu-for-windows-11-right-click-tried-4-differen" target="_blank" rel="noopener"&#10; &gt;SuperUser: Get Back Old Context Menu for Windows 11&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;この記事は、&lt;strong&gt;再現可能で安全な設定変更の記録&lt;/strong&gt;を目的としているため、コマンドやキー名はそのままの形で掲載した。&lt;/p&gt;&#10;</description></item><item><title>WindowsでOllamaを使うための推奨手順</title><link>https://ai.hack-le.com/windows%E3%81%A7ollama%E3%82%92%E4%BD%BF%E3%81%86%E3%81%9F%E3%82%81%E3%81%AE%E6%8E%A8%E5%A5%A8%E6%89%8B%E9%A0%86/</link><pubDate>Mon, 27 Oct 2025 19:25:22 +0900</pubDate><guid>https://ai.hack-le.com/windows%E3%81%A7ollama%E3%82%92%E4%BD%BF%E3%81%86%E3%81%9F%E3%82%81%E3%81%AE%E6%8E%A8%E5%A5%A8%E6%89%8B%E9%A0%86/</guid><description>&lt;h2 id="最も推奨される方法公式windows版をインストール"&gt;最も推奨される方法：公式Windows版をインストール&#10;&lt;/h2&gt;&lt;h3 id="概要"&gt;概要&#10;&lt;/h3&gt;&lt;p&gt;2024年後半から、OllamaはWindows向けに&lt;strong&gt;ネイティブ実行可能な公式ビルド&lt;/strong&gt;を提供している。&lt;br&gt;&#10;インストーラ形式で導入でき、追加の仮想環境（WSLやDocker）は不要である。&lt;br&gt;&#10;&lt;strong&gt;一般ユーザーから開発者まで、すべての用途でこの方法が推奨される。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h3 id="手順"&gt;手順&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;公式サイトからインストーラをダウンロード&lt;/strong&gt; &lt;a class="link" href="https://ollama.com/download" target="_blank" rel="noopener"&#10; &gt;https://ollama.com/download&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;インストーラを実行&lt;/strong&gt; ダウンロードした &lt;code&gt;OllamaSetup.exe&lt;/code&gt; を起動し、指示に従ってセットアップする。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;動作確認&lt;/strong&gt; インストール後、PowerShellまたはWindows Terminalで以下を実行する。 &lt;code&gt;ollama run llama3&lt;/code&gt; 初回実行時にモデルが自動ダウンロードされ、以降はローカルで推論が行われる。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="特徴"&gt;特徴&#10;&lt;/h3&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;項目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;内容&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;対応GPU&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;NVIDIA GPU（CUDA対応）推奨。CPUモードも可&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;既定の保存先&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;C:\Users\&amp;lt;ユーザー名&amp;gt;\.ollama&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;自動起動&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;サービスとして常駐（再起動時も利用可）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;環境変数&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;OLLAMA_HOST&lt;/code&gt;, &lt;code&gt;OLLAMA_MODELS&lt;/code&gt;, &lt;code&gt;OLLAMA_API_KEY&lt;/code&gt;などが設定可能&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="代替方法wsl上でlinux版ollamaを動かす"&gt;代替方法：WSL上でLinux版Ollamaを動かす&#10;&lt;/h2&gt;&lt;h3 id="概要-1"&gt;概要&#10;&lt;/h3&gt;&lt;p&gt;Linux向けのOllamaバイナリを、WSL2環境（例：Ubuntu）で動作させる方法。&lt;br&gt;&#10;GPUを利用したい場合は、&lt;strong&gt;Windows上のCUDAサポートが有効化されたWSL2&lt;/strong&gt;が必要。&lt;br&gt;&#10;ただし、公式Windows版の登場により、この方法は&lt;strong&gt;非推奨&lt;/strong&gt;になりつつある。&lt;/p&gt;&#10;&lt;h3 id="手順ubuntu-on-wsl2"&gt;手順（Ubuntu on WSL2）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://ollama.com/install.sh | sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama run llama3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;※ GPUを使う場合は、NVIDIAドライバがWindowsホストにインストールされており、WSL統合が有効である必要がある。&lt;/p&gt;&#10;&lt;h3 id="向いているケース"&gt;向いているケース&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;WSL上で他のLinuxツールと連携させたい場合&lt;/li&gt;&#10;&lt;li&gt;サーバ的に扱いたい（例：FlaskやFastAPI経由でOllama APIを呼び出す）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="docker版開発検証用途向け"&gt;Docker版（開発・検証用途向け）&#10;&lt;/h2&gt;&lt;p&gt;OllamaはDockerイメージも提供しており、環境を隔離して動かしたい場合に有効である。&lt;/p&gt;&#10;&lt;h3 id="手順-1"&gt;手順&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d -p 11434:11434 ollama/ollama&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Windows環境でGPUを使いたい場合は、Docker Desktop設定で 「&lt;strong&gt;Use the WSL 2 based engine」および「GPU support&lt;/strong&gt;」 を有効にする必要がある。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="利用例"&gt;利用例&#10;&lt;/h2&gt;&lt;h3 id="モデルの一覧確認"&gt;モデルの一覧確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama list&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="モデルのダウンロード"&gt;モデルのダウンロード&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ollama pull mistral&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="apiとして利用"&gt;APIとして利用&#10;&lt;/h3&gt;&lt;p&gt;OllamaはローカルHTTPサーバを起動するため、以下のようにcurlでアクセス可能。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://localhost:11434/api/generate -d &amp;#34;{ \&amp;#34;model\&amp;#34;: \&amp;#34;llama3\&amp;#34;, \&amp;#34;prompt\&amp;#34;: \&amp;#34;Hello\&amp;#34; }&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="推奨構成まとめ"&gt;推奨構成まとめ&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;利用形態&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;推奨方法&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;備考&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一般ユーザー・開発者&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;公式Windows版&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最も安定・簡単&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Linux互換ツールと併用&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;WSL2上のOllama&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;非推奨（用途限定）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;実験・検証・CI環境&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Docker版&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;軽量な検証用&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="補足windows環境でのトラブル回避"&gt;補足：Windows環境でのトラブル回避&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;PATH設定&lt;/strong&gt;：インストール時に自動設定されるが、&lt;code&gt;ollama&lt;/code&gt;が認識されない場合は再ログインを行う。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;GPU未検出&lt;/strong&gt;：NVIDIAドライバを最新に更新し、&lt;code&gt;nvidia-smi&lt;/code&gt;がWindows上で動作することを確認する。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;WSLとの干渉&lt;/strong&gt;：同時にLinux版Ollamaを起動しているとポート衝突（11434）が発生するため注意。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;WindowsでOllamaを使う場合、&lt;strong&gt;公式Windows版インストーラから導入するのが最も推奨&lt;/strong&gt;される。&lt;br&gt;&#10;これにより、GPU利用・サービス常駐・API連携などが容易に実現でき、WSLやDockerを併用する必要がない。&lt;/p&gt;&#10;&lt;p&gt;参考：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;公式サイト：&lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"&#10; &gt;https://ollama.com/&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;ドキュメント：&lt;a class="link" href="https://github.com/ollama/ollama" target="_blank" rel="noopener"&#10; &gt;https://github.com/ollama/ollama&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>SSH鍵方式の変遷とEd25519への移行メモ</title><link>https://ai.hack-le.com/ssh%E9%8D%B5%E6%96%B9%E5%BC%8F%E3%81%AE%E5%A4%89%E9%81%B7%E3%81%A8ed25519%E3%81%B8%E3%81%AE%E7%A7%BB%E8%A1%8C%E3%83%A1%E3%83%A2/</link><pubDate>Mon, 27 Oct 2025 18:58:20 +0900</pubDate><guid>https://ai.hack-le.com/ssh%E9%8D%B5%E6%96%B9%E5%BC%8F%E3%81%AE%E5%A4%89%E9%81%B7%E3%81%A8ed25519%E3%81%B8%E3%81%AE%E7%A7%BB%E8%A1%8C%E3%83%A1%E3%83%A2/</guid><description>&lt;p&gt;長年SSH鍵を生成する際には &lt;code&gt;ssh-keygen -t rsa&lt;/code&gt; が定番であった。しかし近年、セキュリティ界隈では「Ed25519」方式が推奨されるようになっている。本記事ではRSAからEd25519への変遷を整理し、その背景と注意点を備忘録としてまとめる。&lt;/p&gt;&#10;&lt;h2 id="rsaの現状と課題"&gt;RSAの現状と課題&#10;&lt;/h2&gt;&lt;p&gt;RSAは公開鍵暗号の古典的方式であり、長年にわたって安定して使われてきた。現在でも2048bitまたは4096bitの鍵長を採用すれば、現実的な攻撃に対して十分な強度を持つ。しかしRSAには次のような課題がある。&lt;/p&gt;&#10;&lt;p&gt;第一に、鍵生成・署名・検証の計算コストが大きい。特に組み込み機器や仮想環境ではパフォーマンス低下が無視できない。第二に、十分な安全性を確保するには鍵長を増やす必要があり、その結果として鍵サイズや通信オーバーヘッドが増加する。第三に、量子計算の実用化が進めばRSAも楕円曲線暗号も同様に破られる可能性があるため、将来的な耐性は限定的である。&lt;/p&gt;&#10;&lt;p&gt;このようにRSAは依然として安全ではあるが、効率面で時代遅れとなりつつある。&lt;/p&gt;&#10;&lt;h2 id="ed25519とは何か"&gt;Ed25519とは何か&#10;&lt;/h2&gt;&lt;p&gt;Ed25519は楕円曲線暗号の一種であり、正式には「Edwards curve over the prime field 2²⁵⁵−19」を指す。この“25519”という数字は、基礎となる素数体の法 &lt;code&gt;2^255 - 19&lt;/code&gt; に由来する。Daniel J. Bernsteinによって設計され、高速性・安全性・実装の簡潔さを兼ね備えている点が特徴である。&lt;/p&gt;&#10;&lt;p&gt;Ed25519の主な利点は次の通りである。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;鍵と署名のサイズが小さい（64バイト程度）&lt;/li&gt;&#10;&lt;li&gt;署名と検証が高速&lt;/li&gt;&#10;&lt;li&gt;タイミング攻撃などの実装依存の脆弱性に強い&lt;/li&gt;&#10;&lt;li&gt;鍵長の指定が不要で、常に固定長で安全な設計になっている&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このため、OpenSSH 6.5以降ではデフォルト推奨方式としてEd25519が採用されている。&lt;/p&gt;&#10;&lt;h2 id="注意すべき点とトレードオフ"&gt;注意すべき点とトレードオフ&#10;&lt;/h2&gt;&lt;p&gt;Ed25519は優れた方式であるが、RSAの完全上位互換ではない。まず、古いシステムではEd25519鍵に対応していないことがある。特にレガシーなネットワーク機器や古いクラウド環境では、接続できない可能性がある。次に、Ed25519は鍵長を調整できないため、「より長い鍵を使いたい」という要求には応えられない。また、Ed25519の署名方式（EdDSA）はRSAのようにX.509やPGP証明書体系と互換性がない。&lt;/p&gt;&#10;&lt;p&gt;したがって現実的には、&lt;strong&gt;新規環境ではEd25519を採用し、古い環境との互換性を保つためにRSAも併用する&lt;/strong&gt;のが妥当である。&lt;/p&gt;&#10;&lt;h2 id="ed25519鍵の作成方法"&gt;Ed25519鍵の作成方法&#10;&lt;/h2&gt;&lt;p&gt;Ed25519鍵を生成する手順はRSAとほとんど同じである。違いは&lt;code&gt;-t&lt;/code&gt;オプションだけである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh-keygen -t ed25519 -C &lt;span class="s2"&gt;&amp;#34;your_email@example.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上記コマンドを実行すると、&lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt;（秘密鍵）と &lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt;（公開鍵）が生成される。公開鍵を接続先サーバーの &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; に追記すれば、すぐに利用可能になる。RSA鍵を残しておきたい場合も問題なく共存でき、SSHクライアントは自動的に適切な鍵を選択する。&lt;/p&gt;&#10;&lt;p&gt;接続先ごとに鍵を明示的に切り替えたい場合は、&lt;code&gt;~/.ssh/config&lt;/code&gt; に以下を記述する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host myserver&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HostName example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User username&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IdentityFile ~/.ssh/id_ed25519&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;どの鍵が使用されているか確認するには、次のように実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -v myserver&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ログに &lt;code&gt;Offering public key: /home/you/.ssh/id_ed25519&lt;/code&gt; と表示されれば、Ed25519鍵が使われている。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;Ed25519は、RSAと比較して速度・安全性・実装の簡潔さの点で優れている。とはいえ、RSAも現状では十分な安全性を維持しており、量子計算機が登場するまではどちらも有効である。結局のところ、SSHで困らない範囲ではどちらを選んでもよいが、&lt;strong&gt;これから新しく鍵を作るならEd25519が自然な選択&lt;/strong&gt;である。&lt;/p&gt;&#10;</description></item><item><title>WSLでpyenvをインストールする方法（推奨構成）</title><link>https://ai.hack-le.com/wsl%E3%81%A7pyenv%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%EF%BC%88%E6%8E%A8%E5%A5%A8%E6%A7%8B%E6%88%90%EF%BC%89/</link><pubDate>Mon, 27 Oct 2025 18:33:20 +0900</pubDate><guid>https://ai.hack-le.com/wsl%E3%81%A7pyenv%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%EF%BC%88%E6%8E%A8%E5%A5%A8%E6%A7%8B%E6%88%90%EF%BC%89/</guid><description>&lt;p&gt;&lt;code&gt;pyenv&lt;/code&gt;は複数のPythonバージョンを共存・切り替え可能にするバージョン管理ツールである。&lt;br&gt;&#10;WSL上でPython開発環境を整える際、システム標準のPythonを汚さずに複数環境を扱える点で有用である。&lt;br&gt;&#10;ここでは、WSL2 + Ubuntu環境を前提とした最適な手順を解説する。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="環境前提"&gt;環境前提&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;項目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;内容&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;OS&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Windows 10 / 11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;WSL バージョン&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Linux ディストリビューション&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Ubuntu 22.04 以降&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;権限&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sudo&lt;/code&gt; コマンドが利用可能であること&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="依存パッケージのインストール"&gt;依存パッケージのインストール&#10;&lt;/h2&gt;&lt;p&gt;PythonのビルドにはCコンパイラと各種ライブラリが必要である。これを最初に導入する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; make build-essential libssl-dev zlib1g-dev &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; libncurses5-dev libncursesw5-dev xz-utils tk-dev &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; libffi-dev liblzma-dev python3-openssl git&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これを省略すると、後のPythonビルドで&lt;code&gt;_ssl&lt;/code&gt;や&lt;code&gt;readline&lt;/code&gt;モジュールが欠落する場合がある。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="pyenvのインストール推奨"&gt;pyenvのインストール（推奨）&#10;&lt;/h2&gt;&lt;p&gt;公式GitHubリポジトリから&lt;code&gt;pyenv&lt;/code&gt;を直接取得する。&lt;br&gt;&#10;この方法が最も安全で確実である。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/pyenv/pyenv.git ~/.pyenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;環境変数を設定する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export PYENV_ROOT=&amp;#34;$HOME/.pyenv&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export PATH=&amp;#34;$PYENV_ROOT/bin:$PATH&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;eval &amp;#34;$(pyenv init --path)&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;eval &amp;#34;$(pyenv init -)&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;インストール確認：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出力例：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv 2.4.17&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="pythonバージョンのインストール"&gt;Pythonバージョンのインストール&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;pyenv&lt;/code&gt;が導入できたら、目的のPythonバージョンをインストールする。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv install 3.12.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv global 3.12.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pythonのビルドには数分かかる場合がある。&lt;br&gt;&#10;インストール済みのバージョン一覧を確認する場合は以下を実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv versions&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="任意pyenv-virtualenvの導入"&gt;（任意）&lt;code&gt;pyenv-virtualenv&lt;/code&gt;の導入&#10;&lt;/h2&gt;&lt;p&gt;プロジェクト単位で仮想環境を作成したい場合は、&lt;code&gt;pyenv-virtualenv&lt;/code&gt;を追加する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/pyenv/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;eval &amp;#34;$(pyenv virtualenv-init -)&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用例：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv virtualenv 3.12.7 myenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv activate myenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="apt経由のインストール非推奨"&gt;APT経由のインストール（非推奨）&#10;&lt;/h2&gt;&lt;p&gt;Ubuntuには&lt;code&gt;pyenv&lt;/code&gt;パッケージも存在するが、メンテナンスが遅いため避けるべきである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install pyenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この方法ではプラグイン連携（&lt;code&gt;pyenv-virtualenv&lt;/code&gt;など）が不完全であり、将来的な互換性に問題を生じやすい。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;方法&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;特徴&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;推奨度&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;GitHubからクローンして設定&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最新・再現性が高い&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;★★★★★&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;APTでインストール&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;手軽だが古い&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;★★☆☆☆&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;asdf経由で管理&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;言語統合管理を行いたい場合に有効&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;★★★☆☆&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="補足インストール後の確認"&gt;補足：インストール後の確認&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;pyenv&lt;/code&gt;はPATHやシェルの初期化に依存するため、設定ミスがあると動作しない。&lt;br&gt;&#10;トラブル時は次のコマンドで状態を確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pyenv doctor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出力される指示に従うことで、環境変数の不整合や依存パッケージ不足を修正できる。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="参考url"&gt;参考URL&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/pyenv/pyenv" target="_blank" rel="noopener"&#10; &gt;pyenv公式リポジトリ&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/pyenv/pyenv-virtualenv" target="_blank" rel="noopener"&#10; &gt;pyenv-virtualenv公式リポジトリ&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/pyenv/pyenv/wiki/Common-build-problems" target="_blank" rel="noopener"&#10; &gt;pyenv wiki: Common build problems&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;この手順に従えば、WSL上で安定かつ最新の&lt;code&gt;pyenv&lt;/code&gt;環境を構築できる。&lt;br&gt;&#10;再現性が高く、他の開発環境と同等のPython構成を維持できる点で最も推奨される方法である。&lt;/p&gt;&#10;</description></item><item><title>Linux/WSLでghqをインストールする方法</title><link>https://ai.hack-le.com/wsl%E3%81%A7ghq%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 27 Oct 2025 18:22:58 +0900</pubDate><guid>https://ai.hack-le.com/wsl%E3%81%A7ghq%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;&lt;code&gt;ghq&lt;/code&gt;は、リポジトリを一元的に管理するためのCLIツールである。GitHubやGitLabのリポジトリを一貫したパスで管理し、開発環境を整理するのに非常に有効である。&lt;br&gt;&#10;WSL上ではLinux環境として動作するため、Go製のツールである&lt;code&gt;ghq&lt;/code&gt;を直接ビルド・配置するのが最も適している。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;項目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;内容&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;OS&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Windows 10 / 11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;WSL バージョン&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Linux ディストリビューション&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Ubuntu 22.04 以降&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Go言語&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1.19 以上（&lt;code&gt;go install&lt;/code&gt;コマンド対応バージョン）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Goが未インストールの場合は、先にGoのインストール手順（前記事参照）を実施する。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="推奨方法go-installで直接インストールする"&gt;推奨方法：&lt;code&gt;go install&lt;/code&gt;で直接インストールする&#10;&lt;/h2&gt;&lt;p&gt;最も標準的で再現性が高い方法は、Go公式ツールチェーンを用いたインストールである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/x-motemen/ghq@latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;インストール後、&lt;code&gt;~/go/bin&lt;/code&gt; にバイナリが配置されるため、パスを通す。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export PATH=$PATH:$(go env GOPATH)/bin&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;動作確認を行う。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ghq --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで&lt;code&gt;ghq&lt;/code&gt;が利用可能となる。&lt;br&gt;&#10;Goのモジュール管理機能を用いるため、バージョン指定（例：&lt;code&gt;@v1.5.0&lt;/code&gt;）も柔軟に対応できる。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="代替方法apt経由非推奨"&gt;代替方法：APT経由（非推奨）&#10;&lt;/h2&gt;&lt;p&gt;Ubuntuリポジトリにも&lt;code&gt;ghq&lt;/code&gt;パッケージが存在するが、更新が遅くバージョンが古い。&lt;br&gt;&#10;そのため、最新版を利用したい場合には不向きである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install ghq&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この方法は環境構築を自動化したい場合（例：AnsibleやDockerfileなど）には有効だが、開発者自身の利用には推奨されない。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="ソースからのビルド特殊用途向け"&gt;ソースからのビルド（特殊用途向け）&#10;&lt;/h2&gt;&lt;p&gt;カスタマイズが必要な場合や、&lt;code&gt;ghq&lt;/code&gt;の開発版を試したい場合は、手動でビルドできる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/x-motemen/ghq.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ghq&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;デフォルトでは&lt;code&gt;$GOPATH/bin&lt;/code&gt;にバイナリが生成される。&lt;br&gt;&#10;この方法は、Go開発環境の内部構造を理解している場合にのみ選択すべきである。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;方法&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;特徴&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;推奨度&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;go install github.com/x-motemen/ghq@latest&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最新版を簡単に導入できる&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;★★★★★&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;apt install ghq&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;システム管理に統合されるが古い&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;★★☆☆☆&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ソースからビルド&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;開発・検証向け&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;★★★☆☆&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="補足環境変数設定の確認"&gt;補足：環境変数設定の確認&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ghq&lt;/code&gt;は内部で&lt;code&gt;git&lt;/code&gt;コマンドを利用するため、&lt;code&gt;git&lt;/code&gt;がインストールされていることを確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;また、デフォルトのリポジトリ保存パスは &lt;code&gt;~/.ghq&lt;/code&gt; である。&lt;br&gt;&#10;変更したい場合は環境変数で指定する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export GHQ_ROOT=~/dev/src&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;p&gt;この構成を採用すれば、WSL上でもLinux環境と同様に&lt;code&gt;ghq&lt;/code&gt;が安定動作し、GitHubリポジトリの管理を効率化できる。&lt;/p&gt;&#10;</description></item><item><title>Linux/WSLでGo言語をインストールする方法</title><link>https://ai.hack-le.com/wsl%E3%81%A7go%E8%A8%80%E8%AA%9E%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 27 Oct 2025 18:17:58 +0900</pubDate><guid>https://ai.hack-le.com/wsl%E3%81%A7go%E8%A8%80%E8%AA%9E%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;Windows Subsystem for Linux（WSL）は、Windows上でLinux環境を軽量に動作させる仕組みである。Go言語を利用する際も、Windowsネイティブ版よりもWSL環境にインストールすることで、Linux開発環境と同等の挙動が得られるため推奨される。本記事では、WSL上でGoをインストールする推奨手順を整理する。&lt;/p&gt;&#10;&lt;h2 id="環境の前提"&gt;環境の前提&#10;&lt;/h2&gt;&lt;p&gt;本記事の手順は、次の環境を想定している。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;項目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;内容&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;OS&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Windows 10 / 11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;WSL バージョン&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Linux ディストリビューション&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Ubuntu 22.04 以降&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;管理者権限&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sudo&lt;/code&gt; が利用可能であること&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Goのバージョン管理やインストールパスに関する操作を行うため、ユーザーがシステムディレクトリへアクセスできることが前提となる。&lt;/p&gt;&#10;&lt;h2 id="公式バイナリによるインストール推奨"&gt;公式バイナリによるインストール（推奨）&#10;&lt;/h2&gt;&lt;p&gt;最も再現性が高く、常に最新バージョンを利用できる方法は、Go公式サイトからバイナリを取得して直接展開する手法である。この方法では、ディストリビューションに依存せず安定して動作する。&lt;/p&gt;&#10;&lt;h3 id="手順"&gt;手順&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;Go公式ダウンロードページ（&lt;a class="link" href="https://go.dev/dl/" target="_blank" rel="noopener"&#10; &gt;https://go.dev/dl/&lt;/a&gt;）を確認し、最新版のURLを取得する。&lt;/li&gt;&#10;&lt;li&gt;以下のコマンドを実行してGoをインストールする。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://go.dev/dl/go1.23.3.linux-amd64.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -rf /usr/local/go&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tar -C /usr/local -xzf go1.23.3.linux-amd64.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;環境変数を設定する。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export PATH=$PATH:/usr/local/go/bin&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;インストールを確認する。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これでGoの動作環境が整う。バージョンを切り替えたい場合は、同手順で新しいバイナリを展開すればよい。&lt;/p&gt;&#10;&lt;h2 id="aptによるインストール"&gt;APTによるインストール&#10;&lt;/h2&gt;&lt;p&gt;UbuntuのパッケージマネージャであるAPTを利用してインストールすることも可能である。&lt;br&gt;&#10;ただし、APT経由で提供されるバージョンは古い傾向があるため、最新機能を利用する開発には適さない。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install golang&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上記でインストールされるバージョンを確認する場合は以下を実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apt show golang&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;軽量な開発環境を一時的に構築する場合や、システムアップデートと連動させたい場合にのみ選択肢となる。&lt;/p&gt;&#10;&lt;h2 id="asdfによるバージョン管理"&gt;asdfによるバージョン管理&#10;&lt;/h2&gt;&lt;p&gt;複数バージョンのGoを利用したい場合、&lt;code&gt;asdf&lt;/code&gt;などのバージョン管理ツールを利用すると便利である。&lt;code&gt;asdf&lt;/code&gt;はプラグインを追加することで、任意の言語を統一的に管理できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install git curl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;. &amp;#34;$HOME/.asdf/asdf.sh&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;asdf plugin-add golang https://github.com/kennyp/asdf-golang.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;asdf install golang latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;asdf global golang latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この方法では、プロジェクトごとにGoバージョンを固定できるため、チーム開発での再現性確保に有効である。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;WSL環境でGo言語をインストールする場合、最も安定して推奨されるのは&lt;strong&gt;公式バイナリを用いる方法&lt;/strong&gt;である。APTによるインストールは簡便だがバージョンが古い傾向にあり、長期的な利用には不向きである。複数バージョンを扱う必要がある場合は&lt;code&gt;asdf&lt;/code&gt;を導入するのが適している。&lt;/p&gt;&#10;&lt;p&gt;本記事の手順に従えば、WSL環境上でGo言語の開発を迅速に開始できる。&lt;/p&gt;&#10;</description></item><item><title>Windows 11でKeyhacをスタートアップに登録する方法</title><link>https://ai.hack-le.com/windows-11%E3%81%A7keyhac%E3%82%92%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 27 Oct 2025 18:10:02 +0900</pubDate><guid>https://ai.hack-le.com/windows-11%E3%81%A7keyhac%E3%82%92%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;Windowsでキーリマップを柔軟に行いたい場合、Keyhacは非常に便利なツールである。Pythonスクリプトによるカスタマイズが可能で、Emacsライクな操作なども容易に実現できる。しかし、Windowsの起動時にKeyhacを自動起動させる設定を忘れがちなユーザーも多い。本稿では、Windows 11環境でKeyhacを確実にスタートアップに登録する手順を整理する。&lt;/p&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;p&gt;本記事はWindows 11環境を前提とする。また、Keyhacがすでにインストール済みであり、手動で起動できる状態にあることを前提とする。Keyhacは公式サイトまたはGitHubリポジトリから入手可能で、インストーラー版またはzip版のどちらでも問題ない。&lt;/p&gt;&#10;&lt;h2 id="keyhacの実行ファイルを確認する"&gt;Keyhacの実行ファイルを確認する&#10;&lt;/h2&gt;&lt;p&gt;まず、Keyhacの実行ファイル（&lt;code&gt;keyhac.exe&lt;/code&gt;）の場所を確認する。通常は以下のいずれかのパスに存在する。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;インストーラー版の場合 &lt;code&gt;C:\Users\&amp;lt;ユーザー名&amp;gt;\AppData\Local\Programs\Keyhac\keyhac.exe&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;zip版の場合 解凍先の任意フォルダ内に &lt;code&gt;keyhac.exe&lt;/code&gt; がある。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;この実行ファイルの絶対パスを後の手順で使用するため、エクスプローラで確認しておく。&lt;/p&gt;&#10;&lt;h2 id="スタートアップフォルダを開く"&gt;スタートアップフォルダを開く&#10;&lt;/h2&gt;&lt;p&gt;Windows 11では、スタートアップフォルダにショートカットを配置することで、起動時に自動実行できる。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Win + R&lt;/strong&gt; を押して「ファイル名を指定して実行」ダイアログを開く。&lt;/li&gt;&#10;&lt;li&gt;次のコマンドを入力してEnterを押す。 &lt;code&gt;shell:startup&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;エクスプローラが開き、「スタートアップ」フォルダが表示される。ここに配置されたショートカットはWindowsのログイン時に自動実行される。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="ショートカットを作成して登録する"&gt;ショートカットを作成して登録する&#10;&lt;/h2&gt;&lt;p&gt;次に、Keyhacを起動するショートカットを作成し、スタートアップフォルダに配置する。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;keyhac.exe&lt;/code&gt; を右クリックし、「ショートカットの作成」を選択する。&lt;/li&gt;&#10;&lt;li&gt;作成されたショートカットファイルを、先ほど開いた「スタートアップ」フォルダにドラッグ＆ドロップする。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;この操作により、次回以降のWindows起動時にKeyhacが自動起動するようになる。&lt;/p&gt;&#10;&lt;h2 id="管理者権限での実行設定必要に応じて"&gt;管理者権限での実行設定（必要に応じて）&#10;&lt;/h2&gt;&lt;p&gt;Keyhacは他のアプリケーションのキーボードイベントをフックするため、管理者権限で実行しないと動作が制限される場合がある。もしキー入力が効かない、または一部のウィンドウで反応しない場合は以下の設定を行う。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;スタートアップフォルダ内のKeyhacショートカットを右クリックし、「プロパティ」を開く。&lt;/li&gt;&#10;&lt;li&gt;「ショートカット」タブの「詳細設定」をクリックする。&lt;/li&gt;&#10;&lt;li&gt;「管理者として実行」にチェックを入れる。&lt;/li&gt;&#10;&lt;li&gt;OKを押して設定を保存する。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;なお、UAC（ユーザーアカウント制御）の設定によっては、起動時に確認ダイアログが表示される。この挙動を避けたい場合は、次節の「タスクスケジューラによる登録」を用いるとよい。&lt;/p&gt;&#10;&lt;h2 id="タスクスケジューラを使う方法代替手段"&gt;タスクスケジューラを使う方法（代替手段）&#10;&lt;/h2&gt;&lt;p&gt;より確実に管理者権限でKeyhacを起動したい場合は、タスクスケジューラを利用する。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Winキー&lt;/strong&gt;を押して「タスクスケジューラ」と入力し、起動する。&lt;/li&gt;&#10;&lt;li&gt;右側の「タスクの作成」をクリックする。&lt;/li&gt;&#10;&lt;li&gt;「全般」タブで次の設定を行う。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;名前：&lt;code&gt;Keyhac AutoStart&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;「最上位の特権で実行する」にチェック&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;「トリガー」タブ → 「新規」 → 「ログオン時」を選択&lt;/li&gt;&#10;&lt;li&gt;「操作」タブ → 「新規」 → 「プログラムの開始」 → &lt;code&gt;keyhac.exe&lt;/code&gt; のパスを指定&lt;/li&gt;&#10;&lt;li&gt;「OK」を押して保存する。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;この方法では、管理者権限付きでKeyhacが起動するため、全てのアプリケーションでキーマップが有効になる。&lt;/p&gt;&#10;&lt;h2 id="動作確認"&gt;動作確認&#10;&lt;/h2&gt;&lt;p&gt;設定後、Windowsを再起動する。ログイン後にKeyhacのアイコンがタスクトレイに表示されていれば、スタートアップ登録は成功である。表示されない場合は、ショートカットのパスや権限設定を再確認する。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;Windows 11でKeyhacをスタートアップに登録するには、&lt;code&gt;shell:startup&lt;/code&gt; で開いたスタートアップフォルダにショートカットを置くのが基本である。管理者権限が必要な場合は、ショートカットのプロパティで「管理者として実行」を有効化するか、タスクスケジューラを用いる。これにより、起動時に自動でKeyhacが立ち上がり、常時快適なキーバインド環境を維持できる。&lt;/p&gt;&#10;</description></item><item><title>Collabora Online を支える基盤としての Nextcloud と ownCloud</title><link>https://ai.hack-le.com/collabora-online-%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E5%9F%BA%E7%9B%A4%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AE-nextcloud-%E3%81%A8-owncloud/</link><pubDate>Sat, 25 Oct 2025 17:26:45 +0900</pubDate><guid>https://ai.hack-le.com/collabora-online-%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E5%9F%BA%E7%9B%A4%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AE-nextcloud-%E3%81%A8-owncloud/</guid><description>&lt;p&gt;オープンソースでオフィス文書を編集できる &lt;strong&gt;Collabora Online&lt;/strong&gt; を自前で運用しようとすると、まずその基盤となるストレージ／コラボレーション環境を選ぶ必要がある。&lt;br&gt;&#10;代表的な選択肢が &lt;strong&gt;Nextcloud&lt;/strong&gt; と &lt;strong&gt;ownCloud&lt;/strong&gt; である。両者は見かけ上よく似ているが、理念も開発体制も異なり、運用の思想に明確な差がある。&lt;br&gt;&#10;本稿では、表面的な機能比較ではなく、それぞれの設計思想、運用実態、そして現実的な選択肢を整理する。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="owncloud--安定基盤としての伝統的設計"&gt;ownCloud ― 安定基盤としての伝統的設計&#10;&lt;/h2&gt;&lt;p&gt;ownCloud は 2010 年に発足した老舗のセルフホスト型クラウドソフトウェアであり、ファイル同期と共有を目的に設計されている。&lt;br&gt;&#10;商用版とコミュニティ版を分離する &lt;strong&gt;オープンコアモデル&lt;/strong&gt; を採用しており、拡張機能やサポートは企業契約に含まれる。&lt;br&gt;&#10;構造は比較的保守的で、データ同期や認証の仕組みは堅牢である一方、PHP やデータベースの更新追随が遅れる傾向がある。&lt;br&gt;&#10;Collabora Online との統合は可能だが、設定や維持には手作業が多く、企業利用では安定するまで調整が必要になる。&lt;br&gt;&#10;開発の主軸は現在「Infinite Scale」という Go 言語ベースの新アーキテクチャに移行しており、旧来版とは非互換であるため、過渡期の揺らぎが存在する。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="nextcloud--自律的クラウドを目指す統合基盤"&gt;Nextcloud ― 自律的クラウドを目指す統合基盤&#10;&lt;/h2&gt;&lt;p&gt;Nextcloud は 2016 年、ownCloud の創設者が「オープンソースを閉じすぎている」として分岐させたプロジェクトである。&lt;br&gt;&#10;その根本思想は &lt;strong&gt;データ主権（digital sovereignty）&lt;/strong&gt; にあり、ユーザーがクラウドサービスのすべてを自分で運営できる世界を志向している。&lt;br&gt;&#10;この理念から、単なるストレージではなく、ファイル・チャット・カレンダー・メール・Office まで統合した「自己完結型クラウド環境」として発展した。&lt;br&gt;&#10;多機能化が批判される一方で、アプリ構成を選択的に無効化できる柔軟性があり、Files と Office のみを残した軽量運用も現実的である。&lt;br&gt;&#10;Collabora Online とは公式に統合されており、設定は GUI ベースで完結するため、運用安定性の面でも優位にある。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="nextcloud-aio-と-macos-環境"&gt;Nextcloud AIO と macOS 環境&#10;&lt;/h2&gt;&lt;p&gt;Nextcloud は公式に &lt;strong&gt;AIO（All-In-One）&lt;/strong&gt; イメージを提供しており、Docker 上で Nextcloud 本体、DB、Collabora、Proxy をまとめて構築できる。&lt;br&gt;&#10;初期構築が容易で、試験導入に適している。&lt;br&gt;&#10;macOS では以前 Docker Desktop の互換性が低かったが、現在は公式で &lt;strong&gt;OrbStack を推奨&lt;/strong&gt; しており、Linux に近い挙動を得られる。&lt;br&gt;&#10;ただし OrbStack 自体は新しく、長期安定運用を前提とするなら Linux ホストで動かすのが無難である。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="比較と現実的選択"&gt;比較と現実的選択&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;観点&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ownCloud&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Nextcloud&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;開発体制&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;商用主体、安定重視&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;コミュニティ主体、開発活発&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Collabora連携&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;手動設定・限定的&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;公式統合・自動設定&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;拡張思想&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ファイル共有に特化&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;自前クラウド統合を志向&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;運用の安定性&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;機能限定で安定&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;アップデート頻度高く柔軟&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;長期将来性&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Infinite Scale移行期&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;現行Hubが成熟&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;結論として、&lt;strong&gt;Collabora Online の基盤としては Nextcloud のほうが現実的&lt;/strong&gt;である。&lt;br&gt;&#10;Nextcloud は多機能だが取捨選択が容易で、AIO によって導入の障壁も下がった。&lt;br&gt;&#10;ownCloud は基盤としての安定性を保っているものの、Collabora 連携や将来的な移行負担を考えると慎重な選定が必要である。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;Nextcloud は「自分でクラウドを運営する」という理念のもと、機能を抱え込みながらも自由に選べる統合環境を提供している。&lt;br&gt;&#10;一方で ownCloud は「堅牢なファイル共有基盤」として完成しており、理念は対照的である。&lt;br&gt;&#10;Collabora Online を中心に置く場合、Nextcloud は設定・更新・運用の全体で合理的に設計されており、&lt;br&gt;&#10;まず AIO と OrbStack で試し、最終的に Linux 環境で安定化させる構成が最も現実的な落としどころとなる。&lt;/p&gt;&#10;</description></item><item><title>雲の中に消える責任──ガバメントクラウドという現代日本の鏡</title><link>https://ai.hack-le.com/%E9%9B%B2%E3%81%AE%E4%B8%AD%E3%81%AB%E6%B6%88%E3%81%88%E3%82%8B%E8%B2%AC%E4%BB%BB%E2%94%80%E2%94%80%E3%82%AC%E3%83%90%E3%83%A1%E3%83%B3%E3%83%88%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%81%A8%E3%81%84/</link><pubDate>Mon, 20 Oct 2025 10:07:42 +0900</pubDate><guid>https://ai.hack-le.com/%E9%9B%B2%E3%81%AE%E4%B8%AD%E3%81%AB%E6%B6%88%E3%81%88%E3%82%8B%E8%B2%AC%E4%BB%BB%E2%94%80%E2%94%80%E3%82%AC%E3%83%90%E3%83%A1%E3%83%B3%E3%83%88%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%81%A8%E3%81%84/</guid><description>&lt;p&gt;日本の「ガバメントクラウド」は、表向きには行政の効率化を掲げる。デジタル庁が旗を振り、AWSやAzureといった外資クラウドが並ぶ。だが、その設計思想を覗けば、単なる技術選定ではなく、&lt;strong&gt;国家の主権構造そのもの&lt;/strong&gt;が露出している。&lt;br&gt;&#10;行政データを国外企業のクラウドに預けるとは、技術的合理性では説明しきれない決断である。セキュリティ要件は形式的に満たしているだろうが、地政学的リスク、つまり「アメリカと敵対したらどうするのか」という問いを封印して成り立つ脆い信仰である。&lt;br&gt;&#10;国家インフラが外資の都合に左右される構造は、もはや政治の領域であり、技術者だけでは語れぬ。だが現実には、行政の制度設計から政治の視点が抜け、仕様書の中にすべてを押し込めた。技術が政治を代行している。そこに根本的な歪みがある。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;技術信仰と官僚制の共鳴&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;巨大SaaSを運営してきた技術者ほど、「止まらない」「自動化」「統一化」を善と信じる。AWSが落ちることを想定しない。自治体ごとの差異など「例外」として排除する。その思想は官僚制と驚くほど親和的である。&lt;br&gt;&#10;官僚にとっての理想は、全国を一律に制御することだ。設定一つで全自治体を動かせる。現場の裁量を残すより、中央から統制した方が秩序を保ちやすい。SaaSの思想と官僚の統治感覚が重なり、「行政をクラウド化する」という夢が生まれた。&lt;br&gt;&#10;だがそれは本来の自治の死でもある。地方自治体はデータの主権を持たず、障害が起きても「クラウド事業者のせい」と言えるだけ。責任が拡散し、どこにも帰らない構造が出来上がる。&lt;strong&gt;クラウドとは責任の蒸発装置&lt;/strong&gt;なのである。&lt;/p&gt;&#10;&lt;p&gt;地方が動かぬ理由を「クラウド人材不足」と言うのは方便にすぎない。真実は「やる気がない」のではなく、「やると危ない」からやらないのである。&lt;br&gt;&#10;自治体職員は知っている。契約の責任範囲は曖昧で、障害が起きてもベンダーは逃げ、最後は役所のせいになる。成功しても評価されず、失敗すれば職を失う。そんな仕組みで誰が手を挙げるか。だから“動かないことで抵抗する”。これが日本行政の伝統的サボタージュだ。&lt;br&gt;&#10;「補助金付きで導入せよ」と中央が圧をかけても、現場は静かにやり過ごす。報告書の言葉だけ進み、実体は止まったまま。ガバメントクラウドの移行率が伸びないのは、技術力の問題ではなく、&lt;strong&gt;政治的・心理的拒否の現れ&lt;/strong&gt;である。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;クラウドとは何だったのか&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;クラウドはかつて「インフラの革命」と呼ばれた。だが本質は違う。エンジニアにとってのクラウドとは、&lt;strong&gt;責任を分散させるための構造&lt;/strong&gt;である。&lt;br&gt;&#10;オンプレサーバが落ちれば担当者が責められる。AWSが落ちれば「世界的障害で仕方ない」。同じダウンタイムでも、罪の重さが変わる。クラウドは責任の転送装置であり、社会的免責の制度化であった。&lt;br&gt;&#10;エンジニアがクラウドを好むのは、性能ではなく“安心して失敗できる”からだ。官僚がクラウドを好むのも同じ理由だ。“誰も責められない仕組み”があるからである。行政がクラウドを選んだのは、効率ではなく&lt;strong&gt;責任を曖昧にするため&lt;/strong&gt;だった。&lt;/p&gt;&#10;&lt;p&gt;オンプレの障害は「前方不注意」、クラウドの障害は「津波」だ。&lt;br&gt;&#10;前者は個人の過失として叩かれ、後者は「可哀想」で済む。社会全体がこの論理で動いている。小さな失敗は責任を問われ、大きな崩壊は「仕方ない」とされる。&lt;br&gt;&#10;この非対称な倫理が、クラウドと行政を結びつけた。クラウド障害が起きれば「グローバル障害」としてニュースになる。だが誰も怒らない。責任は空に昇り、雲散霧消する。&lt;br&gt;&#10;つまり、ガバメントクラウドとは国家規模での“津波化”である。責任の所在が失われ、誰も悪くない社会が出来上がる。&lt;/p&gt;&#10;&lt;p&gt;クラウドは便利で強力だ。だがその本質は、責任を再配置し、個人から制度へ、制度から虚空へと押し流す装置である。&lt;br&gt;&#10;日本のガバメントクラウドは、技術的課題よりも倫理的課題を抱えている。問うべきは「どのクラウドを使うか」ではなく、「誰が責任を取る構造になっているか」である。&lt;br&gt;&#10;それが問われぬ限り、日本はクラウド国家ではなく、&lt;strong&gt;責任の蒸発した国家&lt;/strong&gt;になる。&lt;/p&gt;&#10;</description></item><item><title>macOS launchctl の bootstrap と bootout コマンドの使い方</title><link>https://ai.hack-le.com/macos-launchctl-%E3%81%AE-bootstrap-%E3%81%A8-bootout-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/</link><pubDate>Wed, 08 Oct 2025 17:21:45 +0900</pubDate><guid>https://ai.hack-le.com/macos-launchctl-%E3%81%AE-bootstrap-%E3%81%A8-bootout-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/</guid><description>&lt;p&gt;macOS では、バックグラウンドで動作するサービス（デーモンやエージェント）を管理するために &lt;code&gt;launchd&lt;/code&gt; という仕組みが用いられており、これを制御するコマンドが &lt;code&gt;launchctl&lt;/code&gt; である。従来は &lt;code&gt;load&lt;/code&gt; と &lt;code&gt;unload&lt;/code&gt; というサブコマンドが使われていたが、macOS 10.11 El Capitan 以降、これらは「レガシーサブコマンド」として扱われ、代わりに &lt;code&gt;bootstrap&lt;/code&gt; と &lt;code&gt;bootout&lt;/code&gt; が推奨されるようになった。ただし実際には、2025年現在も多くの記事やスクリプトで従来の &lt;code&gt;load&lt;/code&gt;/&lt;code&gt;unload&lt;/code&gt; が使われ続けているのが現状である。&lt;/p&gt;&#10;&lt;p&gt;本記事では、公式に推奨されている &lt;code&gt;bootstrap&lt;/code&gt; と &lt;code&gt;bootout&lt;/code&gt; の使い方について解説する。なお、この記事で扱う内容は macOS 10.11 以降を前提としている。&lt;/p&gt;&#10;&lt;h2 id="bootstrap-と-bootout-の基本"&gt;bootstrap と bootout の基本&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bootstrap&lt;/code&gt; と &lt;code&gt;bootout&lt;/code&gt; は、それぞれ従来の &lt;code&gt;load&lt;/code&gt; と &lt;code&gt;unload&lt;/code&gt; に相当するコマンドである。最大の違いは、&lt;strong&gt;ドメインを明示的に指定する必要がある&lt;/strong&gt;という点だ。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;bootstrap&lt;/code&gt;: サービスをドメインに登録して起動する（&lt;code&gt;load&lt;/code&gt; の代替）&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;bootout&lt;/code&gt;: サービスを停止してドメインから削除する（&lt;code&gt;unload&lt;/code&gt; の代替）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;従来の方式では、plist ファイルのパスから暗黙的にドメインが判別されていたが、新しい方式では明示的に指定することで、より正確な制御が可能になるという設計思想である。&lt;/p&gt;&#10;&lt;h2 id="ドメインの種類と意味"&gt;ドメインの種類と意味&#10;&lt;/h2&gt;&lt;p&gt;launchd におけるドメインとは、サービスがどのレベル・どのユーザーのために動作するかを表す概念である。主なドメインは以下の3種類だ。&lt;/p&gt;&#10;&lt;h3 id="system-ドメイン"&gt;system ドメイン&#10;&lt;/h3&gt;&lt;p&gt;システム全体で動作するデーモンのためのドメインである。root 権限で実行され、すべてのユーザーに影響する。通常、&lt;code&gt;/Library/LaunchDaemons/&lt;/code&gt; に配置された plist ファイルがこのドメインで動作する。&lt;/p&gt;&#10;&lt;h3 id="guiuid-ドメイン"&gt;gui/UID ドメイン&#10;&lt;/h3&gt;&lt;p&gt;特定のユーザーがグラフィカルログイン（GUI セッション）している間だけ動作するエージェントのためのドメインである。UID はユーザー ID を表す数値で、macOS では最初に作成されたユーザーは通常 501 となる。自分の UID は &lt;code&gt;id -u&lt;/code&gt; コマンドで確認できる。&lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt; や &lt;code&gt;/Library/LaunchAgents/&lt;/code&gt; に配置されたエージェントは、基本的にこのドメインで動作する。&lt;/p&gt;&#10;&lt;h3 id="useruid-ドメイン"&gt;user/UID ドメイン&#10;&lt;/h3&gt;&lt;p&gt;特定のユーザー権限で動作するが、ログインの有無に関わらず常駐するバックグラウンドサービスのためのドメインである。GUI は使用できないが、PC 起動中は常に動き続ける。このドメインは macOS 10.11 以降で追加された比較的新しい概念である。&lt;/p&gt;&#10;&lt;h2 id="基本的な使い方"&gt;基本的な使い方&#10;&lt;/h2&gt;&lt;h3 id="システムデーモンの登録と削除"&gt;システムデーモンの登録と削除&#10;&lt;/h3&gt;&lt;p&gt;システム全体で動作するデーモンを扱う場合、&lt;code&gt;system&lt;/code&gt; ドメインを指定する。root 権限が必要なため、&lt;code&gt;sudo&lt;/code&gt; を付けて実行する必要がある。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 登録（起動）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.daemon.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 削除（停止）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl bootout system /Library/LaunchDaemons/com.example.daemon.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ユーザーエージェントの登録と削除"&gt;ユーザーエージェントの登録と削除&#10;&lt;/h3&gt;&lt;p&gt;ログイン中のユーザーのために動作するエージェントを扱う場合、&lt;code&gt;gui/UID&lt;/code&gt; ドメインを指定する。まず自分の UID を確認してから、その値を使ってコマンドを実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# UID を確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;id -u&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 例: 501 と表示される&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 登録（起動）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl bootstrap gui/501 ~/Library/LaunchAgents/com.example.agent.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 削除（停止）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl bootout gui/501 ~/Library/LaunchAgents/com.example.agent.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;スクリプト内で動的に UID を取得する場合は、以下のように記述できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在ログイン中のユーザーの UID を取得&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;USER_ID=$(id -u)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 登録&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl bootstrap gui/$USER_ID ~/Library/LaunchAgents/com.example.agent.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 削除&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl bootout gui/$USER_ID ~/Library/LaunchAgents/com.example.agent.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="サービスの状態確認"&gt;サービスの状態確認&#10;&lt;/h3&gt;&lt;p&gt;登録されているサービスの一覧を確認するには、&lt;code&gt;launchctl list&lt;/code&gt; コマンドを使う。特定のサービスを grep で絞り込むことも可能だ。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# すべてのサービスを表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 特定のサービスを検索&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl list | grep com.example&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;より詳細な情報を得るには、&lt;code&gt;launchctl print&lt;/code&gt; コマンドを使う。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# システムドメインの情報を表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl print system&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 特定のユーザードメインの情報を表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl print gui/501&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 特定のサービスの詳細を表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl print gui/501/com.example.agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ただし、&lt;code&gt;print&lt;/code&gt; コマンドの出力形式は公式には構造化されておらず、バージョン間で変更される可能性があるため、スクリプトでのパース処理には依存しないことが推奨されている。&lt;/p&gt;&#10;&lt;h2 id="実行中のサービスの再起動"&gt;実行中のサービスの再起動&#10;&lt;/h2&gt;&lt;p&gt;既に動作しているサービスを再起動したい場合、&lt;code&gt;bootout&lt;/code&gt; してから &lt;code&gt;bootstrap&lt;/code&gt; し直す方法もあるが、より簡単な方法として &lt;code&gt;kickstart&lt;/code&gt; コマンドが用意されている。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# サービスを再起動（-k オプションで既存のインスタンスを終了してから起動）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl kickstart -k gui/501/com.example.agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-k&lt;/code&gt; オプションを付けると、既に動作中のインスタンスを終了してから新しいインスタンスを起動する。オプションなしで実行すると、既に動作中の場合はエラーとなる。&lt;/p&gt;&#10;&lt;h2 id="enable-と-disable-の使い分け"&gt;enable と disable の使い分け&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bootstrap&lt;/code&gt;/&lt;code&gt;bootout&lt;/code&gt; とは別に、&lt;code&gt;enable&lt;/code&gt; と &lt;code&gt;disable&lt;/code&gt; というサブコマンドも存在する。これらはサービスを有効化・無効化するためのもので、次回のブート時やログイン時にサービスを自動起動するかどうかを制御する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# サービスを無効化（次回から自動起動しない）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl disable system/com.example.daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# サービスを有効化（次回から自動起動する）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl enable system/com.example.daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意点として、&lt;code&gt;disable&lt;/code&gt; でサービスを無効化した後は、単に &lt;code&gt;bootstrap&lt;/code&gt; しようとしてもエラーになる。再度有効にするには、まず &lt;code&gt;enable&lt;/code&gt; を実行してから &lt;code&gt;bootstrap&lt;/code&gt; する必要がある。&lt;/p&gt;&#10;&lt;h2 id="従来の-loadunload-との対応関係"&gt;従来の load/unload との対応関係&#10;&lt;/h2&gt;&lt;p&gt;従来の方式と新しい方式の対応関係をまとめると、以下のようになる。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;従来の方式&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;新しい方式&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;launchctl load /Library/LaunchDaemons/service.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sudo launchctl bootstrap system /Library/LaunchDaemons/service.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;launchctl unload /Library/LaunchDaemons/service.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sudo launchctl bootout system /Library/LaunchDaemons/service.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;launchctl load ~/Library/LaunchAgents/agent.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/agent.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;launchctl unload ~/Library/LaunchAgents/agent.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/agent.plist&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;従来の方式では plist ファイルのパスから自動的にドメインが判別されていたが、新しい方式ではドメインを明示的に指定する必要がある。この変更により、より正確な制御が可能になったとされているが、実際には記述量が増え、コマンドも覚えにくくなったという側面もある。&lt;/p&gt;&#10;&lt;h2 id="よくある問題とトラブルシューティング"&gt;よくある問題とトラブルシューティング&#10;&lt;/h2&gt;&lt;h3 id="permission-denied-エラー"&gt;Permission denied エラー&#10;&lt;/h3&gt;&lt;p&gt;システムドメインのサービスを操作する際に &lt;code&gt;sudo&lt;/code&gt; を付け忘れると、権限エラーが発生する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# エラー例&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl bootstrap system /Library/LaunchDaemons/service.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# → Permission denied&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 正しい実行方法&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl bootstrap system /Library/LaunchDaemons/service.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="operation-now-in-progress-エラー"&gt;Operation now in progress エラー&#10;&lt;/h3&gt;&lt;p&gt;サービスが既に登録されている状態で再度 &lt;code&gt;bootstrap&lt;/code&gt; を実行すると、このエラーが発生する。この場合は、まず &lt;code&gt;bootout&lt;/code&gt; で削除してから再度 &lt;code&gt;bootstrap&lt;/code&gt; する必要がある。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 一度削除してから再登録&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl bootout system /Library/LaunchDaemons/service.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl bootstrap system /Library/LaunchDaemons/service.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;あるいは、前述の &lt;code&gt;kickstart -k&lt;/code&gt; コマンドを使うことで、より簡潔に再起動できる。&lt;/p&gt;&#10;&lt;h3 id="bootstrap-failed-5-inputoutput-error"&gt;Bootstrap failed: 5: Input/output error&#10;&lt;/h3&gt;&lt;p&gt;サービスを &lt;code&gt;disable&lt;/code&gt; した後に &lt;code&gt;bootstrap&lt;/code&gt; しようとすると、このエラーが発生することがある。この場合は、まず &lt;code&gt;enable&lt;/code&gt; で有効化してから &lt;code&gt;bootstrap&lt;/code&gt; する必要がある。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 正しい手順&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl enable system/com.example.daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.daemon.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="sip-によるエラー"&gt;SIP によるエラー&#10;&lt;/h3&gt;&lt;p&gt;System Integrity Protection（SIP）が有効な場合、システムが管理する一部の plist ファイルは変更できない。このような場合、以下のようなエラーメッセージが表示される。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Operation not permitted while System Integrity Protection is engaged&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この場合、基本的には操作を諦めるか、SIP を無効化する必要がある（ただし SIP の無効化はセキュリティリスクを伴うため推奨されない）。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bootstrap&lt;/code&gt; と &lt;code&gt;bootout&lt;/code&gt; は、macOS 10.11 以降で推奨されている launchd サービスの管理コマンドである。従来の &lt;code&gt;load&lt;/code&gt;/&lt;code&gt;unload&lt;/code&gt; と比べて、ドメインを明示的に指定する必要があるため、より正確な制御が可能になった反面、コマンドが冗長になり覚えにくくなったという側面もある。&lt;/p&gt;&#10;&lt;p&gt;実際には、2025年現在も多くの記事やスクリプトで従来の &lt;code&gt;load&lt;/code&gt;/&lt;code&gt;unload&lt;/code&gt; が使われ続けており、これらのコマンドも依然として動作する。ただし、公式には &lt;code&gt;bootstrap&lt;/code&gt;/&lt;code&gt;bootout&lt;/code&gt; の使用が推奨されているため、新しく書くスクリプトではこちらを使うのが望ましいとされている。&lt;/p&gt;&#10;&lt;p&gt;システムの根幹に関わる launchd の操作は慎重に行う必要がある。特に &lt;code&gt;/Library/LaunchDaemons/&lt;/code&gt; や &lt;code&gt;/System/Library/&lt;/code&gt; 以下のファイルを扱う際は、誤った操作がシステム全体に影響を及ぼす可能性があるため、十分に注意して作業を進めることが重要である。&lt;/p&gt;&#10;&lt;h2 id="出典"&gt;出典&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;Stack Overflow: &lt;a class="link" href="https://stackoverflow.com/questions/57412590/launchd-confusion-on-the-sematics-of-bootstrap-bootout-for-controlling-services" target="_blank" rel="noopener"&#10; &gt;launchd: Confusion on the sematics of bootstrap/bootout for controlling services on macOS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Ask Different: &lt;a class="link" href="https://apple.stackexchange.com/questions/366281/launchd-confusion-on-semantics-of-bootstrap-and-bootout-etc-after-reading-manu" target="_blank" rel="noopener"&#10; &gt;launchd: Confusion on semantics of bootstrap and bootout etc. after reading manual pages&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Alan Siu&amp;rsquo;s Blog: &lt;a class="link" href="https://www.alansiu.net/2023/11/15/launchctl-new-subcommand-basics-for-macos/" target="_blank" rel="noopener"&#10; &gt;launchctl &amp;ldquo;new&amp;rdquo; subcommand basics for macOS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;SS64.com: &lt;a class="link" href="https://ss64.com/mac/launchctl.html" target="_blank" rel="noopener"&#10; &gt;launchctl Man Page - macOS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;The Terminal Blogger: &lt;a class="link" href="https://joelsenders.wordpress.com/2019/03/14/dear-launchctl-were-all-using-you-wrong/" target="_blank" rel="noopener"&#10; &gt;Dear Launchctl, We&amp;rsquo;re All Using You Wrong&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Babo D&amp;rsquo;s Corner: &lt;a class="link" href="https://babodee.wordpress.com/2016/04/09/launchctl-2-0-syntax/" target="_blank" rel="noopener"&#10; &gt;Launchctl 2.0 Syntax&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>ARPを使ってネットワーク内の特定機器のIPアドレスを効率的に見つける方法</title><link>https://ai.hack-le.com/arp%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E5%86%85%E3%81%AE%E7%89%B9%E5%AE%9A%E6%A9%9F%E5%99%A8%E3%81%AEip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9/</link><pubDate>Sun, 21 Sep 2025 21:11:22 +0900</pubDate><guid>https://ai.hack-le.com/arp%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E5%86%85%E3%81%AE%E7%89%B9%E5%AE%9A%E6%A9%9F%E5%99%A8%E3%81%AEip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9/</guid><description>&lt;p&gt;ネットワーク管理において、特定の機器のIPアドレスを素早く特定する必要がある場面は多い。特にMACアドレスは分かっているが、DHCPによって動的にIPアドレスが割り当てられている環境では、従来のIPアドレス総当たり方式では非効率である。このような状況でARP（Address Resolution Protocol）テーブルを活用することで、効率的に目的の機器を発見できる。&lt;/p&gt;&#10;&lt;p&gt;ARPは、同一ネットワークセグメント内でIPアドレスとMACアドレスの対応関係を管理するプロトコルである。ネットワーク通信が発生する際、OSは自動的にARPテーブルを更新し、最近通信した機器の情報を保持している。この仕組みを利用することで、ネットワーク全体をスキャンした後、ARPテーブルから目的のMACアドレスを持つ機器のIPアドレスを直接抽出できる。&lt;/p&gt;&#10;&lt;h2 id="実行環境と前提条件"&gt;実行環境と前提条件&#10;&lt;/h2&gt;&lt;p&gt;本記事の手順はmacOS、Linux、Windowsの各環境で実行可能である。ただし、一部のコマンドには管理者権限が必要となる。また、対象機器は同一ネットワークセグメント内に存在し、ファイアウォール等でICMPパケット（ping）をブロックしていないことが前提となる。&lt;/p&gt;&#10;&lt;h2 id="基本的なarp発見手順"&gt;基本的なARP発見手順&#10;&lt;/h2&gt;&lt;p&gt;最も基本的な手順は、まずネットワーク全体に対してping応答を送信し、その結果生成されるARPテーブルから目的の機器を抽出する方法である。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ネットワーク全体の生存確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -sn 192.168.1.0/24&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ARPテーブルから特定MACアドレスを検索&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;arp -a | grep &amp;#34;b8:27:eb&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上記の例では、&lt;code&gt;192.168.1.0/24&lt;/code&gt;のネットワークレンジに対してping応答確認を実行し、その後ARPテーブルから&lt;code&gt;b8:27:eb&lt;/code&gt;で始まるMACアドレスを検索している。&lt;code&gt;nmap -sn&lt;/code&gt;オプションは、ポートスキャンを実行せずにホストの生存確認のみを行うため、処理が高速である。&lt;/p&gt;&#10;&lt;p&gt;nmapが利用できない環境では、標準的なpingコマンドを使用したスクリプトでも代替可能である：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for i in {1..254}; do&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ping -c 1 -W 1 192.168.1.$i &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wait&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;arp -a | grep &amp;#34;b8:27:eb&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このスクリプトでは、IPアドレスの範囲を並行処理でpingし、完了後にARPテーブルを確認している。ただし、処理時間の観点からnmapの使用が推奨される。&lt;/p&gt;&#10;&lt;h2 id="arp-scanツールを使用した高速検出"&gt;arp-scanツールを使用した高速検出&#10;&lt;/h2&gt;&lt;p&gt;より確実で高速な検出を実現するには、専用ツールであるarp-scanの使用が効果的である。arp-scanは、ARPリクエストを直接送信するため、pingに応答しない機器でもMACアドレスベースでの検出が可能である。&lt;/p&gt;&#10;&lt;p&gt;macOSでのインストール：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install arp-scan&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Linux（Ubuntu/Debian）でのインストール：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install arp-scan&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基本的な使用方法：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ローカルネットワーク全体をスキャン&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo arp-scan --local | grep &amp;#34;b8:27:eb&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 特定のネットワークレンジを指定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo arp-scan 192.168.1.0/24 | grep &amp;#34;b8:27:eb&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;arp-scanの利点は、ICMPパケット（ping）がブロックされている環境でも動作することである。ARPは同一セグメント内での通信に必須のプロトコルであるため、通常のファイアウォール設定でブロックされることは稀である。また、arp-scanは結果を構造化された形式で出力するため、スクリプト処理にも適している。&lt;/p&gt;&#10;&lt;h2 id="raspberry-pi機器の特定における実践的応用"&gt;Raspberry Pi機器の特定における実践的応用&#10;&lt;/h2&gt;&lt;p&gt;Raspberry Piを例とした具体的な応用例を示す。Raspberry Piは、製造時期やモデルによって異なるMACアドレスプリフィックスを使用している。&lt;/p&gt;&#10;&lt;p&gt;主要なRaspberry PiのMACアドレスプリフィックス：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;b8:27:eb&lt;/code&gt; - 初期のRaspberry Pi（Pi 1, 2, 3の初期モデル）&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;dc:a6:32&lt;/code&gt; - 新しいRaspberry Pi（Pi 3後期モデル以降、Pi 4、Pi Zero 2W等）&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;e4:5f:01&lt;/code&gt; - 一部のPi 4モデル&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;d8:3a:dd&lt;/code&gt; - 最新の一部モデル&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;複数のプリフィックスを同時に検索する場合：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo arp-scan --local | grep -E &amp;#34;(b8:27:eb|dc:a6:32|e4:5f:01|d8:3a:dd)&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;実際の出力例：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.1.105 b8:27:eb:12:34:56 Raspberry Pi Trading Ltd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.1.108 dc:a6:32:78:9a:bc Raspberry Pi Trading Ltd&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この結果から、&lt;code&gt;192.168.1.105&lt;/code&gt;と&lt;code&gt;192.168.1.108&lt;/code&gt;にRaspberry Pi機器が存在することが確認できる。さらに詳細な情報が必要な場合は、検出されたIPアドレスに対してSSH接続やWebブラウザでのアクセスを試行することで、具体的なサービス内容を確認できる。&lt;/p&gt;&#10;&lt;h2 id="トラブルシューティングとパフォーマンス最適化"&gt;トラブルシューティングとパフォーマンス最適化&#10;&lt;/h2&gt;&lt;p&gt;ARPテーブルベースの検出で問題が発生する場合の対処法について説明する。最も一般的な問題は、ARPテーブルエントリの有効期限切れである。多くのOSでは、ARPエントリは数分から数十分で自動的に削除される。そのため、スキャン実行から時間が経過した後にARPテーブルを確認しても、目的の機器が見つからない場合がある。&lt;/p&gt;&#10;&lt;p&gt;この問題を回避するには、スキャンとARPテーブル確認を連続して実行する必要がある：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -sn 192.168.1.0/24 &amp;amp;&amp;amp; arp -a | grep &amp;#34;target_mac_prefix&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;また、一部の機器はICMPパケットをブロックしている場合がある。このような環境では、arp-scanの使用が必須となる。arp-scanでも検出できない場合は、対象機器のネットワーク設定やファイアウォール設定を確認する必要がある。&lt;/p&gt;&#10;&lt;p&gt;パフォーマンスを向上させるには、nmapの並行処理オプションを調整できる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -sn -T5 --min-parallelism 100 192.168.1.0/24&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ただし、過度な並行処理は、ネットワーク機器に負荷をかける可能性があるため、環境に応じて適切な値を設定することが重要である。&lt;/p&gt;&#10;&lt;h2 id="セキュリティ考慮事項と運用上の注意点"&gt;セキュリティ考慮事項と運用上の注意点&#10;&lt;/h2&gt;&lt;p&gt;ARPスキャンは、ネットワーク上のすべての機器に対してパケットを送信するため、ネットワーク管理者の許可なく実行すべきではない。企業環境や公共のネットワークでは、事前に適切な許可を取得することが必要である。&lt;/p&gt;&#10;&lt;p&gt;また、頻繁なARPスキャンは、ネットワーク監視システムによって異常なトラフィックとして検出される可能性がある。定期的な機器発見が必要な場合は、スキャン間隔を適切に調整し、ネットワーク負荷を最小限に抑える運用を心がけることが重要である。&lt;/p&gt;&#10;&lt;p&gt;検出された機器への不正アクセスは法的な問題を引き起こす可能性があるため、発見した機器に対するアクセスは、適切な権限を持つ範囲内でのみ実行するべきである。特にSSHやWebサービスへのアクセス試行は、正当な理由と適切な権限なしに実行してはならない。&lt;/p&gt;&#10;</description></item><item><title>ghqで高速リポジトリ移動を実現する最小設定</title><link>https://ai.hack-le.com/ghq%E3%81%A7%E9%AB%98%E9%80%9F%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E7%A7%BB%E5%8B%95%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%E6%9C%80%E5%B0%8F%E8%A8%AD%E5%AE%9A/</link><pubDate>Tue, 16 Sep 2025 03:03:42 +0900</pubDate><guid>https://ai.hack-le.com/ghq%E3%81%A7%E9%AB%98%E9%80%9F%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E7%A7%BB%E5%8B%95%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%E6%9C%80%E5%B0%8F%E8%A8%AD%E5%AE%9A/</guid><description>&lt;p&gt;ghqを使ってGitリポジトリを管理している際、複数のリポジトリ間を素早く移動したい場面は日常的に発生する。複雑な設定や多機能なツールの組み合わせではなく、最小限の設定で最大の効果を得る方法を紹介する。&lt;/p&gt;&#10;&lt;h2 id="前提環境"&gt;前提環境&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;ghqがインストールされていること&lt;/li&gt;&#10;&lt;li&gt;fzfがインストールされていること&lt;/li&gt;&#10;&lt;li&gt;Bash または Zsh を使用していること&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;fzfのインストールは以下のコマンドで実行できる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# macOS (Homebrew)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install fzf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Ubuntu/Debian&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install fzf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# CentOS/RHEL&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo yum install fzf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="最小構成での設定方法"&gt;最小構成での設定方法&#10;&lt;/h2&gt;&lt;p&gt;シェルの設定ファイル（&lt;code&gt;.bashrc&lt;/code&gt; または &lt;code&gt;.zshrc&lt;/code&gt;）に以下の1行を追加するだけで、高速なリポジトリ移動が可能になる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias g=&amp;#39;cd $(ghq root)/$(ghq list | fzf)&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定により、&lt;code&gt;g&lt;/code&gt; コマンドを実行するとfzfの絞り込み画面が表示され、リポジトリ名を入力して絞り込み、Enterキーで該当するリポジトリのディレクトリに移動できる。&lt;/p&gt;&#10;&lt;p&gt;設定後は以下のコマンドで設定を反映させる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.zshrc # Zshの場合&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bashrc # Bashの場合&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="実際の使用例"&gt;実際の使用例&#10;&lt;/h2&gt;&lt;p&gt;例えば、以下のようなリポジトリ構成があるとする：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/ghq/github.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── user/my-blog&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── user/api-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── user/frontend-app&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── company/internal-tool&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;g&lt;/code&gt; コマンドを実行すると、fzfの絞り込み画面が表示される。ここで「blog」と入力すると &lt;code&gt;user/my-blog&lt;/code&gt; が絞り込まれ、Enterキーを押すことで即座に該当ディレクトリに移動する。部分一致での検索が可能なため、「front」と入力すれば &lt;code&gt;user/frontend-app&lt;/code&gt; にマッチする。&lt;/p&gt;&#10;&lt;p&gt;このような直感的な操作により、従来の &lt;code&gt;cd&lt;/code&gt; コマンドで長いパスを入力する必要がなくなり、開発効率が大幅に向上する。&lt;/p&gt;&#10;&lt;h2 id="他の選択肢との比較"&gt;他の選択肢との比較&#10;&lt;/h2&gt;&lt;p&gt;リポジトリ移動を効率化する方法として、pecoを使用する選択肢もある。pecoは日本で人気のあるツールで、基本的な絞り込み機能を提供する。しかし、現在ではfzfの方が機能的に優れており、より活発に開発されている状況である。&lt;/p&gt;&#10;&lt;p&gt;fzfとpecoの主な違いは、fzfがプレビュー機能や複数選択機能を標準で備えている点にある。また、GitHubでのスター数を見ると、fzfが60,000以上のスターを獲得している一方で、pecoは7,000程度となっており、コミュニティの規模と活発度に大きな差がある。&lt;/p&gt;&#10;&lt;p&gt;将来的な拡張性を考慮した場合、fzfを選択しておくことで、プレビュー機能やその他の高度な機能を後から追加できる余地が残される。&lt;/p&gt;&#10;</description></item><item><title>macOSでtacコマンドを使えるようにする設定方法</title><link>https://ai.hack-le.com/macos%E3%81%A7tac%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B%E8%A8%AD%E5%AE%9A%E6%96%B9%E6%B3%95/</link><pubDate>Tue, 16 Sep 2025 02:23:36 +0900</pubDate><guid>https://ai.hack-le.com/macos%E3%81%A7tac%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B%E8%A8%AD%E5%AE%9A%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;pecoなどのCLIツールを使用する際に、Linuxでは標準的な&lt;code&gt;tac&lt;/code&gt;コマンドがmacOSでは利用できずエラーが発生することがある。この記事では、macOSで&lt;code&gt;tac&lt;/code&gt;コマンドを使えるようにするための設定手順を記録する。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;検証環境&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;macOS&lt;/li&gt;&#10;&lt;li&gt;Homebrew導入済み&lt;/li&gt;&#10;&lt;li&gt;bash または zsh&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="tacコマンドとは"&gt;tacコマンドとは&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;tac&lt;/code&gt;コマンドは、ファイルの内容を行単位で逆順に出力するLinuxの標準コマンドである。&lt;code&gt;cat&lt;/code&gt;コマンドの逆の動作を行うため、&amp;ldquo;tac&amp;rdquo;（catの逆綴り）という名前が付けられている。主にログファイルの最新エントリから順に表示したい場合や、履歴検索ツールでの逆順処理に使用される。&lt;/p&gt;&#10;&lt;h2 id="macosでのtacコマンド不在問題"&gt;macOSでのtacコマンド不在問題&#10;&lt;/h2&gt;&lt;p&gt;macOSでpecoなどのツールを使用する際に、以下のようなエラーが発生する場合がある：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-bash: tac: command not found&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、macOSのBSD系ユーティリティにはGNU系の&lt;code&gt;tac&lt;/code&gt;コマンドが含まれていないことが原因である。多くのLinux環境で当然のように使用されているコマンドであるため、LinuxからmacOSに移行した際によく遭遇する問題となっている。&lt;/p&gt;&#10;&lt;h2 id="coreutilsパッケージによる解決"&gt;coreutilsパッケージによる解決&#10;&lt;/h2&gt;&lt;p&gt;最も確実で標準的な解決方法は、GNU coreutilsパッケージをHomebrewでインストールすることである。GNU coreutilsは、Linux環境で使用されている基本的なコマンド群をmacOSでも利用できるようにするパッケージである。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install coreutils&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このインストールにより、GNU版の各種コマンドが&lt;code&gt;g&lt;/code&gt;プレフィックス付きで利用可能になる。&lt;code&gt;tac&lt;/code&gt;コマンドの場合は&lt;code&gt;gtac&lt;/code&gt;として使用できるようになる。&lt;/p&gt;&#10;&lt;p&gt;インストール後の動作確認：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo -e &amp;#34;first\nsecond\nthird&amp;#34; | gtac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 出力：&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# third&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# second&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# first&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="エイリアスによる透過的な利用"&gt;エイリアスによる透過的な利用&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;gtac&lt;/code&gt;コマンドが使用できるようになったが、既存のスクリプトや設定で&lt;code&gt;tac&lt;/code&gt;として呼び出される場合に対応するため、エイリアスを設定する必要がある。使用しているシェルの設定ファイルにエイリアスを追加することで、&lt;code&gt;tac&lt;/code&gt;コマンドを&lt;code&gt;gtac&lt;/code&gt;に自動的に変換できる。&lt;/p&gt;&#10;&lt;p&gt;bashを使用している場合は&lt;code&gt;~/.bashrc&lt;/code&gt;または&lt;code&gt;~/.bash_profile&lt;/code&gt;に、zshを使用している場合は&lt;code&gt;~/.zshrc&lt;/code&gt;に以下の設定を追加する：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias tac=&amp;#39;gtac&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;設定を反映させるため、設定ファイルを再読み込みするか、新しいターミナルセッションを開始する：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# bashの場合&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# zshの場合&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.zshrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="設定の確認"&gt;設定の確認&#10;&lt;/h2&gt;&lt;p&gt;エイリアス設定後、&lt;code&gt;tac&lt;/code&gt;コマンドが正常に動作することを確認する：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# tacコマンドのテスト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo -e &amp;#34;line1\nline2\nline3&amp;#34; | tac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 期待される出力：&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# line3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# line2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# line1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;また、エイリアスが正しく設定されているかは&lt;code&gt;alias&lt;/code&gt;コマンドで確認できる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias | grep tac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 出力: alias tac=&amp;#39;gtac&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="pecoでの履歴検索への適用"&gt;pecoでの履歴検索への適用&#10;&lt;/h2&gt;&lt;p&gt;この設定により、pecoを使用した履歴検索で&lt;code&gt;tac&lt;/code&gt;コマンドが正常に動作するようになる。一般的なpeco設定では、コマンド履歴を逆順で表示するために&lt;code&gt;tac&lt;/code&gt;が使用されており、以下のような設定が機能するようになる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 例：pecoを使った履歴検索の設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;function peco-select-history() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; local tac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if which tac &amp;gt; /dev/null; then&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tac=&amp;#34;tac&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; elif which tail &amp;gt; /dev/null; then&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tac=&amp;#34;tail -r&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; BUFFER=$(history -n 1 | eval $tac | peco --query &amp;#34;$LBUFFER&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; CURSOR=$#BUFFER&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zle clear-screen&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;macOSでのtacコマンド不在問題は、GNU coreutilsパッケージのインストールとエイリアス設定により解決できる。この設定により、Linux環境で作成されたスクリプトやツール設定をmacOSでもそのまま利用できるようになる。特にpecoやその他のCLIツールを使用する開発環境において、この設定は必須といえる。同様の手法は、GNU系の他のコマンド（&lt;code&gt;gls&lt;/code&gt;、&lt;code&gt;ggrep&lt;/code&gt;など）にも適用でき、Linux環境との互換性を高めることができる。&lt;/p&gt;&#10;</description></item><item><title>ghqでLAN内のプライベートGiteaサーバーのリポジトリを/etc/hostsで定義したドメインで管理する設定方法</title><link>https://ai.hack-le.com/ghq%E3%81%A7%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88gitea%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%82%92%E7%AE%A1%E7%90%86%E3%81%99/</link><pubDate>Tue, 16 Sep 2025 02:15:07 +0900</pubDate><guid>https://ai.hack-le.com/ghq%E3%81%A7%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88gitea%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%82%92%E7%AE%A1%E7%90%86%E3%81%99/</guid><description>&lt;p&gt;プライベートGiteaサーバーとghqを連携させることで、自宅のリポジトリ管理を効率化できる。この記事では、ローカルネットワーク上のGiteaサーバーをghqで管理するための設定手順を記録する。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;検証環境&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;macOS（ghq導入済み）&lt;/li&gt;&#10;&lt;li&gt;Giteaサーバー：192.168.0.100（HTTPSなし、SSH接続可能）&lt;/li&gt;&#10;&lt;li&gt;対象リポジトリ：user@192.168.0.100:org/repository.git&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="hostsファイルによるエイリアス設定"&gt;hostsファイルによるエイリアス設定&#10;&lt;/h2&gt;&lt;p&gt;プライベートサーバーにわかりやすい名前を付けるため、&lt;code&gt;/etc/hosts&lt;/code&gt;でエイリアスを設定する。これにより、IPアドレスではなく意味のあるドメイン名でリポジトリにアクセスできるようになる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vi /etc/hosts&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下の行を追加する：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.0.100 code.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定により、&lt;code&gt;192.168.0.100&lt;/code&gt;への接続が&lt;code&gt;code.example.com&lt;/code&gt;として扱われる。ドメイン名を使うことで、後からサーバーのIPアドレスが変更されても設定変更が容易になるメリットがある。&lt;/p&gt;&#10;&lt;h2 id="ghqでのhttps接続エラーとその対処"&gt;ghqでのHTTPS接続エラーとその対処&#10;&lt;/h2&gt;&lt;p&gt;初回のghq実行では、HTTPSでの接続エラーが発生する場合がある。これは、プライベートGiteaサーバーでHTTPS証明書が設定されていないことが原因である。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ ghq get code.example.com/org/repository.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;error failed to get &amp;#34;code.example.com/org/repository.git&amp;#34;: unsupported VCS, url=https://code.example.com/org/repository.git: Get &amp;#34;https://code.example.com/org/repository.git?go-get=1&amp;#34;: dial tcp 192.168.0.8:443: connect: connection refused&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このエラーメッセージから、ghqがデフォルトでHTTPS（ポート443）での接続を試行していることがわかる。プライベートサーバーではHTTPS設定を行わないことが多いため、SSHまたはHTTPでの接続に切り替える必要がある。&lt;/p&gt;&#10;&lt;h2 id="gitconfigによるプロトコル変換設定"&gt;gitconfigによるプロトコル変換設定&#10;&lt;/h2&gt;&lt;p&gt;最も効率的な解決方法は、Gitの設定でプロトコル変換を行うことである。&lt;code&gt;~/.gitconfig&lt;/code&gt;に以下の設定を追加することで、HTTPSのURLが自動的にSSHに変換される。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[ghq]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; vcs = git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[url &amp;#34;ssh://code.example.com/&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; insteadOf = https://code.example.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定の&lt;code&gt;url.insteadOf&lt;/code&gt;は、Gitが特定のURLパターンを別のURLに自動変換する機能である。&lt;code&gt;https://code.example.com/&lt;/code&gt;で始まるURLが&lt;code&gt;ssh://code.example.com/&lt;/code&gt;に置き換えられるため、HTTPSでアクセスしようとしても実際にはSSH接続が行われる。&lt;/p&gt;&#10;&lt;p&gt;設定後は、HTTPSのURLを指定してもSSHで接続されるようになる：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ ghq get code.example.com/org/repository.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; clone ssh://code.example.com/org/repository.git -&amp;gt; /Users/username/ghq/code.example.com/org/repository&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="リポジトリの配置とアクセス"&gt;リポジトリの配置とアクセス&#10;&lt;/h2&gt;&lt;p&gt;ghqによってクローンされたリポジトリは、以下のパスに配置される：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/ghq/code.example.com/org/repository/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この階層構造により、複数のGitサーバーやオーガニゼーションのリポジトリを整理して管理できる。ghqは常に&lt;code&gt;ホスト名/ユーザー名またはオーガニゼーション名/リポジトリ名&lt;/code&gt;の形式でディレクトリを作成するため、リポジトリの所在が明確になる。&lt;/p&gt;&#10;&lt;p&gt;日常的な操作では、以下のコマンドが有用である：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 管理しているリポジトリ一覧の表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ghq list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# リポジトリの完全パス表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ghq list --full-path&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 特定リポジトリへの移動&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd $(ghq root)/code.example.com/org/repository&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;プライベートGiteaサーバーとghqの連携において、&lt;code&gt;/etc/hosts&lt;/code&gt;によるエイリアス設定と&lt;code&gt;.gitconfig&lt;/code&gt;でのプロトコル変換設定を組み合わせることで、効率的なリポジトリ管理環境を構築できる。特に&lt;code&gt;.gitconfig&lt;/code&gt;の&lt;code&gt;url.insteadOf&lt;/code&gt;設定により、HTTPSとSSHの違いを意識することなく、統一されたURLでリポジトリにアクセスできるようになることが重要である。この設定により、プライベート開発環境でのリポジトリ管理が大幅に改善される。&lt;/p&gt;&#10;</description></item><item><title>macOSでBash起動時のロケール警告を解決する方法</title><link>https://ai.hack-le.com/macos%E3%81%A7bash%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%AD%E3%82%B1%E3%83%BC%E3%83%AB%E8%AD%A6%E5%91%8A%E3%82%92%E8%A7%A3%E6%B1%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Tue, 16 Sep 2025 01:54:34 +0900</pubDate><guid>https://ai.hack-le.com/macos%E3%81%A7bash%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%AD%E3%82%B1%E3%83%BC%E3%83%AB%E8%AD%A6%E5%91%8A%E3%82%92%E8%A7%A3%E6%B1%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;macOSでシェルをfishからbashに変更した際、ターミナル起動時に以下のような警告が表示されることがある。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-bash: 警告: setlocale: LC_COLLATE: cannot change locale (): No such file or directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この警告は機能上の問題を引き起こすわけではないが、毎回表示されるため作業の邪魔になる。本記事では、この警告を解消する対症療法的な解決方法を記録する。&lt;/p&gt;&#10;&lt;h2 id="環境"&gt;環境&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;macOS（Homebrewでbashをインストール済み）&lt;/li&gt;&#10;&lt;li&gt;シェルをfishからbashに変更後&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;/opt/homebrew/bin/bash&lt;/code&gt;を使用&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="問題の原因分析"&gt;問題の原因分析&#10;&lt;/h2&gt;&lt;h3 id="現在のロケール設定の確認"&gt;現在のロケール設定の確認&#10;&lt;/h3&gt;&lt;p&gt;まず、現在のロケール設定を確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;locale&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;問題がある場合、以下のような出力になることが多い。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LANG=&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_COLLATE=&amp;#34;C&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_CTYPE=&amp;#34;UTF-8&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_MESSAGES=&amp;#34;C&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_MONETARY=&amp;#34;C&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_NUMERIC=&amp;#34;C&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_TIME=&amp;#34;C&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LC_ALL=&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;環境変数の確認も行う。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;env | grep -E &amp;#34;(LANG|LC_)&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドで表示される内容と&lt;code&gt;locale&lt;/code&gt;コマンドの出力に不一致がある場合、設定の競合が発生している可能性が高い。&lt;/p&gt;&#10;&lt;h3 id="根本原因の推定"&gt;根本原因の推定&#10;&lt;/h3&gt;&lt;p&gt;警告メッセージの&lt;code&gt;cannot change locale ():&lt;/code&gt;の括弧内が空になっているのは、どこかでロケール関連の環境変数が空文字列に設定されているためである。これは以下のような要因で発生する可能性がある。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;以前使用していたシェル（fish等）の設定残骸&lt;/li&gt;&#10;&lt;li&gt;システムアップデート時の設定の不整合&lt;/li&gt;&#10;&lt;li&gt;複数のツールによる環境変数の競合&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="解決方法"&gt;解決方法&#10;&lt;/h2&gt;&lt;h3 id="基本的な対症療法"&gt;基本的な対症療法&#10;&lt;/h3&gt;&lt;p&gt;個人用の設定ファイルを作成し、明示的にロケールを設定する。これにより、不完全な設定を上書きできる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#39;export LANG=en_US.UTF-8&amp;#39; &amp;gt; ~/.bash_profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;設定を即座に反映させる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bash_profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="設定内容の選択指針"&gt;設定内容の選択指針&#10;&lt;/h3&gt;&lt;p&gt;ロケール設定には以下の選択肢がある。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;英語環境での自然な並び順を優先する場合（推奨）&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export LANG=en_US.UTF-8&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定により、&lt;code&gt;ls&lt;/code&gt;コマンドやファイルソートで大文字小文字を考慮した辞書順になる。具体的には、&lt;code&gt;Apple&lt;/code&gt;、&lt;code&gt;apple&lt;/code&gt;、&lt;code&gt;Banana&lt;/code&gt;、&lt;code&gt;banana&lt;/code&gt;の順序で表示される。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;純粋なASCII順序を優先する場合&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export LANG=C&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定では、ASCII値順（数字→大文字→小文字）でソートされる。プログラマー向けの厳密な順序だが、一般的な用途では直感的でない順序になることがある。&lt;/p&gt;&#10;&lt;h3 id="設定の確認"&gt;設定の確認&#10;&lt;/h3&gt;&lt;p&gt;設定後、新しいターミナルを開いて以下を確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;locale&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;すべての&lt;code&gt;LC_*&lt;/code&gt;項目が設定したロケール（例：&lt;code&gt;en_US.UTF-8&lt;/code&gt;）になっていれば成功である。また、警告メッセージが表示されなくなることを確認する。&lt;/p&gt;&#10;&lt;h2 id="追加の対処法"&gt;追加の対処法&#10;&lt;/h2&gt;&lt;h3 id="ターミナルアプリ固有の設定確認"&gt;ターミナルアプリ固有の設定確認&#10;&lt;/h3&gt;&lt;p&gt;一部のターミナルアプリケーションは独自の設定ファイルを持つ場合がある。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;#34;/etc/bashrc_$TERM_PROGRAM&amp;#34; 2&amp;gt;/dev/null || echo &amp;#34;Terminal-specific bashrc not found&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="利用可能なロケールの確認"&gt;利用可能なロケールの確認&#10;&lt;/h3&gt;&lt;p&gt;システムでサポートされているロケールを確認したい場合は以下を実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;locale -a | grep -E &amp;#34;(en_US|ja_JP|C$)&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="注意事項"&gt;注意事項&#10;&lt;/h2&gt;&lt;p&gt;この方法は対症療法であり、根本的な原因（どこで空文字列が設定されているか）を解決するものではない。しかし、実用上は十分な解決策となる。&lt;/p&gt;&#10;&lt;p&gt;長期間使用しているシステムでは、様々なツールのインストール・アンインストールにより設定の断片が残存することがある。完全な解決を求める場合は、クリーンインストールが最も確実な方法である。&lt;/p&gt;&#10;&lt;h2 id="参考資料"&gt;参考資料&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://www.gnu.org/software/bash/manual/" target="_blank" rel="noopener"&#10; &gt;Bashマニュアル - GNU&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/" target="_blank" rel="noopener"&#10; &gt;ロケール設定 - Apple Developer Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Reddit投稿精読：災害時のself-hosting</title><link>https://ai.hack-le.com/reddit%E6%8A%95%E7%A8%BF%E7%B2%BE%E8%AA%AD%EF%BC%9A%E7%81%BD%E5%AE%B3%E6%99%82%E3%81%AEself-hosting/</link><pubDate>Sun, 07 Sep 2025 01:43:45 +0900</pubDate><guid>https://ai.hack-le.com/reddit%E6%8A%95%E7%A8%BF%E7%B2%BE%E8%AA%AD%EF%BC%9A%E7%81%BD%E5%AE%B3%E6%99%82%E3%81%AEself-hosting/</guid><description>&lt;p&gt;&lt;a class="link" href="https://www.reddit.com/r/selfhosted/comments/1n8dvpg/selfhosting_in_a_disaster/" target="_blank" rel="noopener"&#10; &gt;Self-hosting in a disaster : r/selfhosted&lt;/a&gt;&lt;/p&gt;&#10;&lt;h2 id="読解対象テキスト"&gt;読解対象テキスト&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Self-hosting in a disaster&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Self Help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Yesterday my area had a level 1 evacuation notice (&amp;#34;be ready&amp;#34;), and I spent about six hours shoving all my important stuff in my car. We&amp;#39;re still at level 1, the people on the other side of the fire aren&amp;#39;t so lucky, but packing my server up (after all the actually important stuff) got me thinking...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;A lot of why I self-host is to get away from the bullshit peddled by Google / etc, but another part is &amp;#34;just in case&amp;#34;, having my own intranet of digital tools in a bad situation. And here I&amp;#39;ve got this great little mini PC and a bunch of resources, but no way to power it on-the-go or during a black out...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;So today to pass the time waiting for the evac notice to clear, I&amp;#39;m considering what I&amp;#39;d want to host during a disaster and what kind of hardware setup I&amp;#39;d need to actually do that...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Has anyone got plans/experience with actually running their setup during an emergency?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="語彙表現学習"&gt;語彙・表現学習&#10;&lt;/h2&gt;&lt;h3 id="重要単語とニュアンス"&gt;重要単語とニュアンス&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;shove&lt;/strong&gt; [動詞]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;基本意味：押し込む、突っ込む&lt;/li&gt;&#10;&lt;li&gt;ニュアンス：pushより乱暴で急いでいる感じ&lt;/li&gt;&#10;&lt;li&gt;感情：焦り、慌て、時間がない状況&lt;/li&gt;&#10;&lt;li&gt;例：「避難準備で慌てて物を車に詰め込む」&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;still&lt;/strong&gt; [副詞]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;この文脈：まだ〜のまま（継続）&lt;/li&gt;&#10;&lt;li&gt;ニュアンス：現状維持への安堵感&lt;/li&gt;&#10;&lt;li&gt;対比への準備：「でも他の人は&amp;hellip;」という流れを示唆&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;bullshit&lt;/strong&gt; [名詞・スラング]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;意味：でたらめ、うんざりする物&lt;/li&gt;&#10;&lt;li&gt;使用場面：技術系でカジュアルに使われる&lt;/li&gt;&#10;&lt;li&gt;この文脈：大手テック企業の押し付けがましいサービス&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;peddle&lt;/strong&gt; [動詞]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;基本意味：行商する、売り歩く&lt;/li&gt;&#10;&lt;li&gt;転用：押し付ける、押し売りする&lt;/li&gt;&#10;&lt;li&gt;ニュアンス：要らないものを無理やり売りつける感覚&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;just in case&lt;/strong&gt; [慣用表現]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;意味：万が一に備えて、念のため&lt;/li&gt;&#10;&lt;li&gt;使用場面：準備や対策の理由として&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;on-the-go&lt;/strong&gt; [慣用表現]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;意味：移動中に、外出先で、持ち運んで&lt;/li&gt;&#10;&lt;li&gt;固定表現：一つの決まった概念&lt;/li&gt;&#10;&lt;li&gt;使用場面：モバイル性能を語る時の定番&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;evac&lt;/strong&gt; [略語]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;正式：evacuation（避難）&lt;/li&gt;&#10;&lt;li&gt;使用分野：軍事・緊急時・技術分野で一般的&lt;/li&gt;&#10;&lt;li&gt;例：evac notice（避難通知）、evac route（避難経路）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;host&lt;/strong&gt; [動詞・技術用語]&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;IT分野：サーバーとして稼働させる、サービスを提供する&lt;/li&gt;&#10;&lt;li&gt;ニュアンス：主体的な選択と管理の意味合い&lt;/li&gt;&#10;&lt;li&gt;例：「災害時にどんなサービスを稼働させたいか」&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="文法構造ポイント"&gt;文法・構造ポイント&#10;&lt;/h2&gt;&lt;h3 id="複雑な文構造の分解"&gt;複雑な文構造の分解&#10;&lt;/h3&gt;&lt;p&gt;&amp;ldquo;&lt;strong&gt;I spent about six hours shoving all my important stuff in my car&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;構造：spend + 時間 + doing&lt;/li&gt;&#10;&lt;li&gt;意味：〜するのに時間を費やす&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&amp;ldquo;&lt;strong&gt;We&amp;rsquo;re still at level 1, the people on the other side of the fire aren&amp;rsquo;t so lucky, but packing my server up got me thinking&amp;hellip;&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;構造：3つの節の並列（接続詞なしのカンマ並列）&lt;/li&gt;&#10;&lt;li&gt;A, B, but C = A で、B だが、C だ&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&amp;ldquo;&lt;strong&gt;after all the actually important stuff&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;省略構造：after (packing) all the actually important stuff&lt;/li&gt;&#10;&lt;li&gt;文脈から動詞部分が省略されている&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&amp;ldquo;&lt;strong&gt;I&amp;rsquo;m considering what I&amp;rsquo;d want to host during a disaster and what kind of hardware setup I&amp;rsquo;d need to actually do that&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;メイン動詞：I&amp;rsquo;m considering&lt;/li&gt;&#10;&lt;li&gt;目的語：2つの疑問詞節の並列&#10;&lt;ol&gt;&#10;&lt;li&gt;what I&amp;rsquo;d want to host during a disaster&lt;/li&gt;&#10;&lt;li&gt;what kind of hardware setup I&amp;rsquo;d need to actually do that&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;that&amp;rdquo;：前の節全体「災害中にホストすること」を指す&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="having構文の理解"&gt;having構文の理解&#10;&lt;/h3&gt;&lt;p&gt;&amp;ldquo;&lt;strong&gt;having my own intranet of digital tools in a bad situation&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;構造：現在分詞の説明用法&lt;/li&gt;&#10;&lt;li&gt;機能：&amp;ldquo;just in case&amp;quot;の具体的説明&lt;/li&gt;&#10;&lt;li&gt;意味：悪い状況でも自分専用のデジタルツール環境を持つこと&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="復習用例文"&gt;復習用例文&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;shove&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;I shoved my clothes into the suitcase at the last minute.&amp;rdquo;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;Stop shoving papers into that drawer!&amp;rdquo;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;peddle&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;They&amp;rsquo;re peddling expensive subscriptions to users.&amp;rdquo;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;I&amp;rsquo;m tired of the ads they peddle on social media.&amp;rdquo;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;&lt;strong&gt;just in case&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;I keep extra batteries just in case of a power outage.&amp;rdquo;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;Save your work frequently, just in case the system crashes.&amp;rdquo;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;&lt;strong&gt;on-the-go&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;This app works perfectly for checking emails on-the-go.&amp;rdquo;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;Mobile gaming has made entertainment on-the-go much better.&amp;rdquo;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="5"&gt;&#10;&lt;li&gt;&lt;strong&gt;host (技術用語)&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;We host our website on our own servers.&amp;rdquo;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;Which services do you host locally?&amp;rdquo;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="6"&gt;&#10;&lt;li&gt;&lt;strong&gt;spend時間doing&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;I spent three hours debugging this issue.&amp;rdquo;&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;She spent the morning organizing her files.&amp;rdquo;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>WSL環境でMac風のpbcopy/pbpasteを実現する方法</title><link>https://ai.hack-le.com/wsl%E7%92%B0%E5%A2%83%E3%81%A7mac%E9%A2%A8%E3%81%AEpbcopy-pbpaste%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Sun, 17 Aug 2025 13:47:19 +0900</pubDate><guid>https://ai.hack-le.com/wsl%E7%92%B0%E5%A2%83%E3%81%A7mac%E9%A2%A8%E3%81%AEpbcopy-pbpaste%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;h2 id="前提環境"&gt;前提環境&#10;&lt;/h2&gt;&lt;p&gt;この記事は以下の環境での動作を前提としている。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Windows 10/11&lt;/li&gt;&#10;&lt;li&gt;WSL2（Windows Subsystem for Linux 2）&lt;/li&gt;&#10;&lt;li&gt;Ubuntu 20.04以降（他のディストリビューションでも同様の手順で可能）&lt;/li&gt;&#10;&lt;li&gt;Bash または Zsh シェル&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="背景と課題"&gt;背景と課題&#10;&lt;/h2&gt;&lt;p&gt;Macユーザーであれば、コマンドラインからクリップボードを操作する際に&lt;code&gt;pbcopy&lt;/code&gt;と&lt;code&gt;pbpaste&lt;/code&gt;コマンドを使用することに慣れているだろう。これらのコマンドは非常に便利で、パイプを使ってテキストをクリップボードにコピーしたり、クリップボードの内容を取得したりできる。&lt;/p&gt;&#10;&lt;p&gt;一方、WSL環境では標準でこのような機能は提供されていない。Linux用のクリップボードツールである&lt;code&gt;xclip&lt;/code&gt;をインストールしても、これはX Window System内でのクリップボード操作に留まり、Windowsのシステムクリップボードとは連携しない。つまり、WSL内で&lt;code&gt;xclip&lt;/code&gt;を使ってコピーした内容を、Windows側のアプリケーションで貼り付けることはできないのである。&lt;/p&gt;&#10;&lt;h2 id="windowsのネイティブなクリップボードapi"&gt;WindowsのネイティブなクリップボードAPI&#10;&lt;/h2&gt;&lt;p&gt;実は、Windowsには&lt;code&gt;clip.exe&lt;/code&gt;というコマンドラインツールが標準で付属している。このツールを使用することで、パイプ経由でテキストをクリップボードに書き込むことが可能である。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#34;Hello World&amp;#34; | clip.exe&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上記のコマンドを実行すると、「Hello World」がWindowsのクリップボードにコピーされ、任意のWindowsアプリケーションで貼り付けることができる。&lt;/p&gt;&#10;&lt;p&gt;ただし、&lt;code&gt;clip.exe&lt;/code&gt;は書き込み専用であり、クリップボードの内容を読み取る機能は提供されていない。そのため、Macの&lt;code&gt;pbpaste&lt;/code&gt;に相当する機能を実現するには別の方法が必要となる。&lt;/p&gt;&#10;&lt;h2 id="powershellを活用したクリップボード読み取り"&gt;PowerShellを活用したクリップボード読み取り&#10;&lt;/h2&gt;&lt;p&gt;Windowsでクリップボードの内容を取得するには、PowerShellの&lt;code&gt;Get-Clipboard&lt;/code&gt;コマンドレットを使用する。WSL内からPowerShellを呼び出すことで、この機能を利用できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;powershell.exe -command &amp;#34;Get-Clipboard&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを実行すると、現在のクリップボードの内容がターミナルに出力される。なお、&lt;code&gt;-command&lt;/code&gt;パラメータは省略可能であり、以下のように短縮して記述することも可能である。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;powershell.exe &amp;#34;Get-Clipboard&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="エイリアスによる利便性の向上"&gt;エイリアスによる利便性の向上&#10;&lt;/h2&gt;&lt;p&gt;毎回長いコマンドを入力するのは非効率的であるため、エイリアスを設定してMacと同様の使い勝手を実現する。使用しているシェルの設定ファイル（Bashの場合は&lt;code&gt;~/.bashrc&lt;/code&gt;、Zshの場合は&lt;code&gt;~/.zshrc&lt;/code&gt;）に以下の行を追加する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias pbcopy=&amp;#39;clip.exe&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias pbpaste=&amp;#39;powershell.exe -command &amp;#34;Get-Clipboard&amp;#34;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;設定を反映するために、シェルを再起動するか、以下のコマンドを実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Bashの場合&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Zshの場合 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.zshrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="実際の使用例"&gt;実際の使用例&#10;&lt;/h2&gt;&lt;p&gt;エイリアスを設定した後は、Macと同様の感覚でクリップボード操作が可能になる。以下に実用的な使用例を示す。&lt;/p&gt;&#10;&lt;h3 id="基本的な使用方法"&gt;基本的な使用方法&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# テキストをクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#34;テスト文字列&amp;#34; | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# クリップボードの内容を表示&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pbpaste&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ファイルの内容をクリップボードにコピー"&gt;ファイルの内容をクリップボードにコピー&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# SSH公開鍵をクリップボードにコピー（GitHubへの登録などに便利）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat ~/.ssh/id_rsa.pub | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 設定ファイルの内容をクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat ~/.vimrc | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="gitとの連携"&gt;Gitとの連携&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 最新5件のコミット履歴をクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git log --oneline -5 | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のブランチ名をクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch --show-current | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のリモートURLをクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git remote get-url origin | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ディレクトリパスの活用"&gt;ディレクトリパスの活用&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のディレクトリパスをクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pwd | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 特定のファイルの絶対パスをクリップボードにコピー&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;readlink -f example.txt | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="パフォーマンスと制限事項"&gt;パフォーマンスと制限事項&#10;&lt;/h2&gt;&lt;p&gt;このアプローチにはいくつかの注意点がある。まず、&lt;code&gt;powershell.exe&lt;/code&gt;の起動には若干の時間がかかるため、&lt;code&gt;pbpaste&lt;/code&gt;の実行速度は純粋なLinuxコマンドと比較して遅くなる。ただし、日常的な使用においては実用上問題となることは少ない。&lt;/p&gt;&#10;&lt;p&gt;また、非常に大きなテキストをクリップボードに格納する場合、PowerShellの制限によって一部のデータが切り取られる可能性がある。通常の開発作業で扱うテキストサイズであれば問題ないが、大容量のデータを扱う場合は注意が必要である。&lt;/p&gt;&#10;&lt;p&gt;さらに、この方法はWSLからWindowsの実行ファイルを呼び出すため、WSL2の場合はネットワークを介した通信が発生する。セキュリティ設定によっては、この通信が制限される可能性もある。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;WSL環境においても、Windowsの標準機能とPowerShellを組み合わせることで、Macの&lt;code&gt;pbcopy&lt;/code&gt;/&lt;code&gt;pbpaste&lt;/code&gt;と同等の機能を実現できる。エイリアスを設定することで、Macからの移行時も違和感なく使用できるようになる。&lt;/p&gt;&#10;&lt;p&gt;この方法の最大の利点は、追加のソフトウェアをインストールすることなく、Windowsの標準機能のみで実現できることである。WSLでの開発効率を向上させる簡単で実用的な設定として、ぜひ活用していただきたい。&lt;/p&gt;&#10;</description></item><item><title>LinuxでmacOS風クリップボード操作を実現するxclipの設定方法</title><link>https://ai.hack-le.com/linux%E3%81%A7macos%E9%A2%A8%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E6%93%8D%E4%BD%9C%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8Bxclip%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%96%B9/</link><pubDate>Sat, 09 Aug 2025 20:03:51 +0900</pubDate><guid>https://ai.hack-le.com/linux%E3%81%A7macos%E9%A2%A8%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E6%93%8D%E4%BD%9C%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8Bxclip%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%96%B9/</guid><description>&lt;p&gt;この記事の内容は、X11ウィンドウシステムを使用するLinux環境で動作確認している。Wayland環境では&lt;code&gt;wl-clipboard&lt;/code&gt;パッケージを使用する必要があるため、事前に使用環境を確認してほしい。また、記事中のコマンド例は、Debian/Ubuntu系ディストリビューションでの実行を前提としている。&lt;/p&gt;&#10;&lt;h2 id="linuxでのcliクリップボード操作の必要性"&gt;LinuxでのCLIクリップボード操作の必要性&#10;&lt;/h2&gt;&lt;p&gt;Linuxでコマンドライン作業をしていると、コマンドの出力結果をブラウザやテキストエディタに貼り付けたい場面が頻繁にある。しかし、標準的なLinux環境では、ターミナル出力を直接システムクリップボードに送る機能が用意されていない。一方、macOSでは&lt;code&gt;pbcopy&lt;/code&gt;と&lt;code&gt;pbpaste&lt;/code&gt;コマンドが標準で提供されており、パイプを使って簡単にクリップボード操作ができる。Linuxでも同様の機能を実現するためのツールが&lt;code&gt;xclip&lt;/code&gt;である。&lt;/p&gt;&#10;&lt;p&gt;xclipは、X11環境でコマンドライン出力をシステムクリップボードに送ったり、クリップボードの内容をターミナルに出力したりできる軽量なユーティリティである。このツールを適切に設定することで、macOSと同じような感覚でクリップボード操作を行うことができる。&lt;/p&gt;&#10;&lt;h2 id="xclipのインストール手順"&gt;xclipのインストール手順&#10;&lt;/h2&gt;&lt;p&gt;xclipのインストール方法は、使用しているLinuxディストリビューションによって異なる。主要なディストリビューションでの手順を以下に示す。&lt;/p&gt;&#10;&lt;p&gt;Debian系（Ubuntu、Linux Mint等）では、aptパッケージマネージャーを使用してインストールできる。まずパッケージリストを更新してから、xclipパッケージをインストールする。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install xclip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Red Hat系（CentOS、RHEL、Fedora等）では、使用しているバージョンに応じてyumまたはdnfを使用する。Fedoraの場合は以下のコマンドでインストールできる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install xclip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CentOS 7やRHEL 7の場合は、EPELリポジトリを有効にしてからインストールする必要がある。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo yum install epel-release&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo yum install xclip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Arch Linuxでは、pacmanパッケージマネージャーを使用してインストールできる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pacman -S xclip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;インストールが完了したら、簡単なテストを行ってxclipが正常に動作することを確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#34;test message&amp;#34; | xclip -selection clipboard&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを実行後、テキストエディタやブラウザでCtrl+Vを押して「test message」が貼り付けられれば、インストールは成功している。&lt;/p&gt;&#10;&lt;h2 id="xclipの基本的な使用方法"&gt;xclipの基本的な使用方法&#10;&lt;/h2&gt;&lt;p&gt;xclipを使用してクリップボード操作を行う場合、主に&lt;code&gt;-selection clipboard&lt;/code&gt;オプションを使用する。このオプションを指定することで、一般的なアプリケーションでCtrl+C/Ctrl+Vで使用するクリップボードにアクセスできる。&lt;/p&gt;&#10;&lt;p&gt;コマンド出力をクリップボードにコピーする場合は、パイプを使ってxclipに出力を渡す。例えば、現在のディレクトリの詳細なファイル一覧をクリップボードにコピーしたい場合は、以下のコマンドを使用する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -la | xclip -selection clipboard&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ファイルの内容をクリップボードにコピーしたい場合は、リダイレクションを使用する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xclip -selection clipboard &amp;lt; file.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;クリップボードの内容を表示したい場合は、&lt;code&gt;-o&lt;/code&gt;オプション（出力オプション）を使用する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xclip -selection clipboard -o&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-selection clipboard&lt;/code&gt;は頻繁に使用するため、&lt;code&gt;-sel clip&lt;/code&gt;と短縮形で記述することも可能である。&lt;/p&gt;&#10;&lt;h2 id="macos風エイリアスの設定方法"&gt;macOS風エイリアスの設定方法&#10;&lt;/h2&gt;&lt;p&gt;MacとLinuxの両方を使用している場合、同じコマンドでクリップボード操作ができると非常に便利である。macOSの&lt;code&gt;pbcopy&lt;/code&gt;と&lt;code&gt;pbpaste&lt;/code&gt;コマンドと同じ感覚で使用できるように、bashまたはzshの設定ファイルにエイリアスを追加する。&lt;/p&gt;&#10;&lt;p&gt;bashを使用している場合は、ホームディレクトリの&lt;code&gt;.bashrc&lt;/code&gt;ファイルに以下の行を追加する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias pbcopy=&amp;#39;xclip -selection clipboard&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alias pbpaste=&amp;#39;xclip -selection clipboard -o&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;zshを使用している場合は、&lt;code&gt;.zshrc&lt;/code&gt;ファイルに同じ内容を追加する。設定を手動で編集するか、以下のコマンドで一括追加できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#39;alias pbcopy=&amp;#34;xclip -selection clipboard&amp;#34;&amp;#39; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#39;alias pbpaste=&amp;#34;xclip -selection clipboard -o&amp;#34;&amp;#39; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;設定後は、macOSと全く同じコマンドでクリップボード操作が可能になる。&lt;/p&gt;&#10;&lt;h2 id="実際の活用例"&gt;実際の活用例&#10;&lt;/h2&gt;&lt;p&gt;エイリアス設定後の具体的な活用例をいくつか紹介する。これらの例は、日常的な開発作業で頻繁に使用する場面である。&lt;/p&gt;&#10;&lt;p&gt;ファイルの内容をクリップボードにコピーする場合：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pbcopy &amp;lt; config.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;コマンド実行結果をクリップボードにコピーする場合：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git log --oneline --graph | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;システム情報をクリップボードにコピーする場合：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uname -a | pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;クリップボードの内容をファイルに保存する場合：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pbpaste &amp;gt; output.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SSH公開鍵をクリップボードにコピーする場合：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pbcopy &amp;lt; ~/.ssh/id_rsa.pub&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらの例のように、パイプやリダイレクションと組み合わせることで、様々な場面でクリップボード操作を活用できる。特に、長いコマンド出力やファイル内容を他のアプリケーションに貼り付ける際に、マウス操作によるコピー&amp;amp;ペーストよりも効率的である。&lt;/p&gt;&#10;&lt;h2 id="その他のクリップボードツールとの比較"&gt;その他のクリップボードツールとの比較&#10;&lt;/h2&gt;&lt;p&gt;X11環境でのクリップボード操作ツールとしては、xclip以外にも&lt;code&gt;xsel&lt;/code&gt;がある。xselも同様の機能を提供するが、xclipの方が一般的に広く使用されており、ドキュメントやコミュニティサポートが充実している。また、パッケージマネージャーでの提供状況もxclipの方が良好である。&lt;/p&gt;&#10;&lt;p&gt;Wayland環境を使用している場合は、&lt;code&gt;wl-clipboard&lt;/code&gt;パッケージの&lt;code&gt;wl-copy&lt;/code&gt;と&lt;code&gt;wl-paste&lt;/code&gt;コマンドを使用する必要がある。使用方法はxclipと類似しているが、オプションの指定方法が異なるため注意が必要である。&lt;/p&gt;&#10;&lt;p&gt;現在の環境がX11かWaylandかを確認するには、以下のコマンドを実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo $XDG_SESSION_TYPE&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出力が「x11」であればxclipを、「wayland」であればwl-clipboardを使用することを推奨する。&lt;/p&gt;&#10;&lt;p&gt;この設定により、LinuxとmacOSの間での作業環境の切り替えが円滑になり、クリップボード操作に関する認知的負荷を軽減できる。特に、複数のOSを使い分けている開発者にとっては、コマンドの統一性が作業効率の向上に大きく貢献する。&lt;/p&gt;&#10;</description></item><item><title>WSL2とHyper-V、Androidエミュレータの関係と最新対応状況</title><link>https://ai.hack-le.com/wsl2%E3%81%A8hyper-v%E3%80%81android%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF%E3%81%AE%E9%96%A2%E4%BF%82%E3%81%A8%E6%9C%80%E6%96%B0%E5%AF%BE%E5%BF%9C%E7%8A%B6%E6%B3%81/</link><pubDate>Fri, 01 Aug 2025 04:43:17 +0900</pubDate><guid>https://ai.hack-le.com/wsl2%E3%81%A8hyper-v%E3%80%81android%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF%E3%81%AE%E9%96%A2%E4%BF%82%E3%81%A8%E6%9C%80%E6%96%B0%E5%AF%BE%E5%BF%9C%E7%8A%B6%E6%B3%81/</guid><description>&lt;h2 id="wsl2の実装基盤としてのhyper-v"&gt;WSL2の実装基盤としてのHyper-V&#10;&lt;/h2&gt;&lt;p&gt;WSL2（Windows Subsystem for Linux 2）は、一見するとLinux環境のように見えるが、実際にはMicrosoftのHyper-V技術を基盤として動作している。WSL2は軽量な仮想マシン（Lightweight Utility VM）として実装されており、この仮想マシンはHyper-V Platform上で稼働している。&lt;/p&gt;&#10;&lt;p&gt;従来のHyper-Vの完全な仮想マシンとは異なり、WSL2はWindowsカーネルと密に統合されているため、ユーザーからはネイティブなLinux環境のように感じられる。しかし、内部的にはHyper-Vエコシステムの一部として機能している点が重要である。&lt;/p&gt;&#10;&lt;h2 id="androidエミュレータとの競合メカニズム"&gt;Androidエミュレータとの競合メカニズム&#10;&lt;/h2&gt;&lt;h3 id="仮想化技術の排他的利用"&gt;仮想化技術の排他的利用&#10;&lt;/h3&gt;&lt;p&gt;BlueStacks、NoxPlayer、LDPlayerなどの多くのAndroidエミュレータは、独自の仮想化技術やVT-x/AMD-Vハードウェア仮想化機能を直接利用している。一方、WSL2がHyper-V Platformを有効にすると、他の仮想化ソフトウェアがハードウェア仮想化機能に直接アクセスできなくなる。&lt;/p&gt;&#10;&lt;p&gt;この現象が発生する理由は、Windowsでは一度に一つのハイパーバイザーしか動作できないためである。Hyper-V Platform（WSL2用）が有効になると、他の仮想化ソフトウェアはネストした仮想化として動作するか、完全に動作不能になってしまう。&lt;/p&gt;&#10;&lt;h3 id="具体的な問題例"&gt;具体的な問題例&#10;&lt;/h3&gt;&lt;p&gt;例えば、開発環境でWSL2を使用してDockerやLinux開発環境を構築している状況で、同時にBlueStacksでモバイルゲームをテストしようとすると、BlueStacksが「仮想化が無効になっています」というエラーメッセージを表示して起動できないという問題が発生する。&lt;/p&gt;&#10;&lt;h2 id="最新のhyper-v対応状況"&gt;最新のHyper-V対応状況&#10;&lt;/h2&gt;&lt;h3 id="bluestacksの対応"&gt;BlueStacksの対応&#10;&lt;/h3&gt;&lt;p&gt;BlueStacks 5はバージョン5.20以降で大幅な改善が図られている。Android 9 Pieインスタンスを使用することで、Hyper-V有効状態でも動作可能になった。さらに最新版ではAndroid 11もHyper-V環境で利用できる。&lt;/p&gt;&#10;&lt;p&gt;公式サイトからBlueStacksをダウンロードする際、システムでHyper-Vが有効になっていることを検出すると、自動的にHyper-V対応版がインストールされる仕組みが導入されている。&lt;/p&gt;&#10;&lt;h3 id="noxplayerの革新的アプローチ"&gt;NoxPlayerの革新的アプローチ&#10;&lt;/h3&gt;&lt;p&gt;NoxPlayerは2022年3月に「世界初のVirtualBoxとHyper-V両対応エミュレータ」として新バージョンをリリースした。この実装により、従来のように仮想化技術を切り替えるためにシステムを再起動する必要がなくなった。&lt;/p&gt;&#10;&lt;p&gt;特筆すべき点は、WSA（Windows Subsystem for Android）やGoogle Play Gamesといった、Hyper-V基盤の他のAndroid実行環境と同時に動作できることである。これにより、開発者やテスターは複数のAndroid環境を同一システム上で利用できるようになった。&lt;/p&gt;&#10;&lt;h3 id="ldplayerの対応状況"&gt;LDPlayerの対応状況&#10;&lt;/h3&gt;&lt;p&gt;LDPlayer 9はVirtualBoxとHyper-Vの両方に対応しているが、パフォーマンス面ではHyper-Vを無効化することが推奨されている。以前のバージョンで発生していたHyper-V環境でのクラッシュ問題は解決済みである。&lt;/p&gt;&#10;&lt;h2 id="解決方法と選択肢"&gt;解決方法と選択肢&#10;&lt;/h2&gt;&lt;h3 id="従来の解決方法"&gt;従来の解決方法&#10;&lt;/h3&gt;&lt;p&gt;問題が発生した場合の従来の対処法は以下の通りである。&lt;/p&gt;&#10;&lt;p&gt;WSL2を犠牲にする場合は、コマンドプロンプトで &lt;code&gt;bcdedit /set hypervisorlaunchtype off&lt;/code&gt; を実行してHyper-Vを無効化し、システムを再起動する。その後WSL2をWSL1に戻すことでAndroidエミュレータが正常に動作するようになる。&lt;/p&gt;&#10;&lt;p&gt;逆にWSL2を優先する場合は、Androidエミュレータの使用を諦めるか、Hyper-V対応版への移行を検討する必要があった。&lt;/p&gt;&#10;&lt;h3 id="現在推奨される解決方法"&gt;現在推奨される解決方法&#10;&lt;/h3&gt;&lt;p&gt;最新の状況では、以下のアプローチが効果的である。&lt;/p&gt;&#10;&lt;p&gt;BlueStacksを使用する場合は、最新版にアップデートしてAndroid 9 Pie以降のインスタンスを作成する。これによりHyper-V環境での安定動作が期待できる。&lt;/p&gt;&#10;&lt;p&gt;NoxPlayerを選択する場合は、Hyper-V対応版を利用することで、WSL2、WSA、Google Play Gamesとの同時利用が可能になる。&lt;/p&gt;&#10;&lt;p&gt;LDPlayerを使用する場合は、最新のLDPlayer 9を導入し、必要に応じてHyper-Vの有効・無効を切り替える運用を検討する。&lt;/p&gt;&#10;&lt;h2 id="開発環境での実践的な運用"&gt;開発環境での実践的な運用&#10;&lt;/h2&gt;&lt;h3 id="推奨構成例"&gt;推奨構成例&#10;&lt;/h3&gt;&lt;p&gt;現代の開発環境では、以下の構成が実用的である。&lt;/p&gt;&#10;&lt;p&gt;WSL2でLinux開発環境とDockerを構築し、同時にNoxPlayerまたは最新のBlueStacksでモバイルアプリケーションのテストを行う。この構成により、仮想化技術の競合を気にすることなく、フルスタック開発環境を構築できる。&lt;/p&gt;&#10;&lt;h3 id="注意点"&gt;注意点&#10;&lt;/h3&gt;&lt;p&gt;ただし、パフォーマンスを最重視する場合は、依然としてHyper-Vを無効化した従来の方法が有効な場合がある。特にリソースが限られたシステムや、高いフレームレートが要求されるゲーム開発では、この点を考慮する必要がある。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;WSL2とAndroidエミュレータの競合問題は、各エミュレータベンダーの技術革新により大幅に改善されている。特にNoxPlayerとBlueStacksの最新版では、Hyper-V環境での安定動作が実現されており、開発者は仮想化技術の切り替えによる煩雑さから解放されつつある。&lt;/p&gt;&#10;&lt;p&gt;ただし、最適なパフォーマンスを求める場合は、用途に応じてHyper-Vの有効・無効を選択することが重要である。現在の技術状況を理解し、自身の開発環境に最適な構成を選択することで、効率的な開発環境を構築できるだろう。&lt;/p&gt;&#10;</description></item><item><title>WSL2でGo開発環境を構築する – パッケージ管理の選択肢と実践</title><link>https://ai.hack-le.com/wsl2%E3%81%A7go%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B-%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E7%AE%A1%E7%90%86%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2/</link><pubDate>Fri, 01 Aug 2025 04:33:23 +0900</pubDate><guid>https://ai.hack-le.com/wsl2%E3%81%A7go%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B-%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E7%AE%A1%E7%90%86%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2/</guid><description>&lt;h2 id="前提環境"&gt;前提環境&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;Windows 11/10 + WSL2&lt;/li&gt;&#10;&lt;li&gt;Ubuntu 22.04 LTS（WSL2上）&lt;/li&gt;&#10;&lt;li&gt;インターネット接続環境&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="goインストール方法の比較検討"&gt;Goインストール方法の比較検討&#10;&lt;/h2&gt;&lt;p&gt;WSL2上でGoの開発環境を構築する際、主に3つの選択肢がある。それぞれの特徴を理解した上で、適切な方法を選択することが重要である。&lt;/p&gt;&#10;&lt;h3 id="公式バイナリによるインストール"&gt;公式バイナリによるインストール&#10;&lt;/h3&gt;&lt;p&gt;Go公式サイトから直接バイナリをダウンロードして &lt;code&gt;/usr/local&lt;/code&gt; にインストールする方法である。最新版が確実に入手できる一方で、アップデート作業が完全に手動となる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 最新版のダウンロード（例：go1.21.5）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd /tmp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://go.dev/dl/go1.21.5.linux-amd64.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 既存版の削除とインストール&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -rf /usr/local/go&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 環境変数設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#39;export PATH=$PATH:/usr/local/go/bin&amp;#39; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この方法は確実性が高いものの、新しいバージョンがリリースされるたびに同じ作業を繰り返す必要がある。&lt;/p&gt;&#10;&lt;h3 id="ubuntu標準パッケージでのインストール"&gt;Ubuntu標準パッケージでのインストール&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;apt&lt;/code&gt; コマンドで標準リポジトリからインストールする最もシンプルな方法である。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install golang-go&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ただし、Ubuntu 22.04の標準リポジトリに含まれるGoは1.18系と古く、最新の言語機能やライブラリが利用できない場合がある。&lt;/p&gt;&#10;&lt;h3 id="ppaを利用したインストール推奨"&gt;PPAを利用したインストール（推奨）&#10;&lt;/h3&gt;&lt;p&gt;Personal Package Archive（PPA）を使用することで、最新のGoを &lt;code&gt;apt&lt;/code&gt; で管理できる。具体的には &lt;code&gt;ppa:longsleep/golang-backports&lt;/code&gt; を利用する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo add-apt-repository ppa:longsleep/golang-backports&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install golang-go&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このPPAはSimon Eisenmann氏によって個人的に維持されており、Go公式Wikiでも推奨されている。通常のパッケージ更新の流れでGoも最新版に更新される利便性がある。&lt;/p&gt;&#10;&lt;h2 id="パッケージ管理ツールの選択理由"&gt;パッケージ管理ツールの選択理由&#10;&lt;/h2&gt;&lt;p&gt;現在のLinux環境では、従来の &lt;code&gt;apt&lt;/code&gt; に加えて &lt;code&gt;snap&lt;/code&gt; というパッケージ管理システムも選択肢として存在する。しかし、snapには以下の課題がある。&lt;/p&gt;&#10;&lt;p&gt;snapはCanonical社が開発した新しいパッケージ形式で、依存関係を含む自己完結型のパッケージを提供する。一見便利に思えるが、実際には起動速度の低下、メモリ使用量の増加、そしてSnapストアがCanonicalの独占管理下にあるという構造的な問題を抱えている。&lt;/p&gt;&#10;&lt;p&gt;Linux コミュニティでは「便利だが本質的ではない」という評価が一般的であり、特に開発環境のような基盤的なツールには従来のパッケージ管理を選択する開発者が多い。&lt;/p&gt;&#10;&lt;h2 id="実際のインストール手順"&gt;実際のインストール手順&#10;&lt;/h2&gt;&lt;p&gt;上記の検討を踏まえ、PPAを使用したインストールを実行する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# PPAリポジトリの追加&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo add-apt-repository ppa:longsleep/golang-backports&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# パッケージリストの更新&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Goのインストール&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install golang-go&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# インストール確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;期待される出力例：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go version go1.21.5 linux/amd64&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="開発環境の設定"&gt;開発環境の設定&#10;&lt;/h2&gt;&lt;p&gt;Goの開発に必要なディレクトリ構造を作成し、環境変数を設定する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Go作業ディレクトリの作成&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p ~/go/{bin,src,pkg}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 環境変数の設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#39;export GOPATH=$HOME/go&amp;#39; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#39;export PATH=$PATH:$GOPATH/bin&amp;#39; &amp;gt;&amp;gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 設定の反映&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;source ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 環境確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go env GOPATH&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go env GOROOT&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="動作確認"&gt;動作確認&#10;&lt;/h2&gt;&lt;p&gt;実際にGoプログラムをビルドして実行し、環境が正しく構築されていることを確認する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# テスト用ディレクトリの作成&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir ~/go/src/hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd ~/go/src/hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# サンプルプログラムの作成&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;lt;&amp;lt; &amp;#39;EOF&amp;#39; &amp;gt; main.go&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;package main&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import &amp;#34;fmt&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func main() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fmt.Println(&amp;#34;Hello, Go on WSL2!&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ビルドと実行&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正常に動作すれば &lt;code&gt;Hello, Go on WSL2!&lt;/code&gt; と出力される。&lt;/p&gt;&#10;&lt;h2 id="今後の運用"&gt;今後の運用&#10;&lt;/h2&gt;&lt;p&gt;PPAを使用している場合、Goのアップデートは通常のシステム更新で自動的に行われる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 定期的なシステム更新でGoも更新される&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この方法により、手動でのバージョン管理作業から解放され、常に最新の安定版を利用できる開発環境が維持される。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;WSL2上でのGo開発環境構築において、複数の選択肢がある中でPPAを利用する方法が実用性と保守性のバランスが取れている。個人管理のリポジトリに依存するリスクはあるものの、長期間の運用実績とGo公式の推奨により、実用的な選択肢として評価できる。&lt;/p&gt;&#10;</description></item><item><title>[音声付き] 英語学習メモその6：Clear Linux廃止記事から学ぶ実用英語表現</title><link>https://ai.hack-le.com/%E9%9F%B3%E5%A3%B0%E4%BB%98%E3%81%8D-%E8%8B%B1%E8%AA%9E%E5%AD%A6%E7%BF%92%E3%83%A1%E3%83%A2%E3%81%9D%E3%81%AE6%EF%BC%9Aclear-linux%E5%BB%83%E6%AD%A2%E8%A8%98%E4%BA%8B%E3%81%8B%E3%82%89%E5%AD%A6/</link><pubDate>Sat, 26 Jul 2025 12:03:59 +0900</pubDate><guid>https://ai.hack-le.com/%E9%9F%B3%E5%A3%B0%E4%BB%98%E3%81%8D-%E8%8B%B1%E8%AA%9E%E5%AD%A6%E7%BF%92%E3%83%A1%E3%83%A2%E3%81%9D%E3%81%AE6%EF%BC%9Aclear-linux%E5%BB%83%E6%AD%A2%E8%A8%98%E4%BA%8B%E3%81%8B%E3%82%89%E5%AD%A6/</guid><description>&lt;p&gt;元ネタ：&lt;a class="link" href="https://www.phoronix.com/news/Intel-Ends-Clear-Linux" target="_blank" rel="noopener"&#10; &gt;Intel Announces It&amp;rsquo;s Shutting Down Clear Linux - Phoronix&lt;/a&gt;&lt;/p&gt;&#10;&lt;h2 id="intel-announces-its-shutting-down-clear-linux"&gt;Intel Announces It&amp;rsquo;s Shutting Down Clear Linux&#10;&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://hack-le.com/wp-content/uploads/2025/07/eng6.mp3" target="_blank" rel="noopener"&#10; &gt;音声ファイル (https://hack-le.com/wp-content/uploads/2025/07/eng6.mp3)&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;Written by &lt;a class="link" href="https://www.michaellarabel.com/" target="_blank" rel="noopener"&#10; &gt;Michael Larabel&lt;/a&gt; in &lt;a class="link" href="https://www.phoronix.com/linux/Intel" target="_blank" rel="noopener"&#10; &gt;Intel&lt;/a&gt; on 18 July 2025 at 06:01 PM EDT. &lt;a class="link" href="https://www.phoronix.com/forums/node/1562120" target="_blank" rel="noopener"&#10; &gt;50 Comments&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;The most depressing news of the week: Intel is ending their performance-optimized Clear Linux distribution. Over the past decade the &lt;a class="link" href="https://www.phoronix.com/search/Clear&amp;#43;Linux" target="_blank" rel="noopener"&#10; &gt;Clear Linux&lt;/a&gt; operating system has shown what&amp;rsquo;s possible with out-of-the-box performance on x86_64 hardware&amp;hellip; Not just for Intel platforms but even showing extremely great performance results on AMD x86_64 too. But with the cost-cutting going on at Intel, Clear Linux is now being sunset.&lt;/p&gt;&#10;&lt;p&gt;Intel put out &lt;a class="link" href="https://community.clearlinux.org/t/all-good-things-come-to-an-end-shutting-down-clear-linux-os/10716" target="_blank" rel="noopener"&#10; &gt;a statement&lt;/a&gt; that Clear Linux is being shutdown:&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&amp;ldquo;After years of innovation and community collaboration, we’re ending support for Clear Linux OS. Effective immediately, Intel will no longer provide security patches, updates, or maintenance for Clear Linux OS, and the Clear Linux OS GitHub repository will be archived in read-only mode. So, if you’re currently using Clear Linux OS, we strongly recommend planning your migration to another actively maintained Linux distribution as soon as possible to ensure ongoing security and stability.&lt;/p&gt;&#10;&lt;p&gt;Rest assured that Intel remains deeply invested in the Linux ecosystem, actively supporting and contributing to various open-source projects and Linux distributions to enable and optimize for Intel hardware.&lt;/p&gt;&#10;&lt;p&gt;A heartfelt thank you to every developer, user, and contributor who helped shape Clear Linux OS over the last 10 years. Your feedback and contributions have been invaluable.&amp;rdquo;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;Heartbreaking. In recent years I heard a few times of Clear Linux potentially being on the chopping-block due to cost-cutting at Intel and trying to emphasize out-of-the-box performance for the major Linux distributions and getting more of their work upstreamed as well. Today though it&amp;rsquo;s finally been made official.&lt;/p&gt;&#10;&lt;p&gt;Clear Linux has delivered many great out-of-the-box performance optimizations for Linux systems and shown what can be done for packaging with profile guided optimizations / link-time optimizations, various kernel tweaks, and other innovations over the years. At least the likes of CachyOS have picked up some of these optimizations. Intel engineers are also working with other major Linux distributions on enhancing their Linux distribution performance too. But those details and whether they will be ramping up those efforts or not remain unclear.&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Clear Linux" class="gallery-image" data-flex-basis="384px" data-flex-grow="160" height="406" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.phoronix.net/image.php?id=framework-12-linux-os&amp;image=framework_12_linux_4_med" width="650"&gt;&lt;/p&gt;&#10;&lt;p&gt;This caps off a week where &lt;a class="link" href="https://www.phoronix.com/news/Shutemov-Intel-Linux-Leaving" target="_blank" rel="noopener"&#10; &gt;a very prominent Linux engineer left Intel&lt;/a&gt;, &lt;a class="link" href="https://www.phoronix.com/news/Intel-SLM-Driver-Orphaned" target="_blank" rel="noopener"&#10; &gt;an upstream Linux driver is now orphaned over another engineer departure&lt;/a&gt;, and various other Intel software engineers working on open-source/Linux also let go as part of the latest restructuring at Intel.&lt;/p&gt;&#10;&lt;p&gt;Intelが長年開発してきた高性能最適化Linuxディストリビューション「Clear Linux」の開発・サポート終了が発表された。コスト削減と戦略転換が背景にある。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="重要語彙表現学習"&gt;重要語彙・表現学習&#10;&lt;/h2&gt;&lt;h3 id="1-sunset動詞--段階的廃止"&gt;1. sunset（動詞）- 段階的廃止&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本的意味&lt;/strong&gt;: 日没、夕日&lt;br&gt;&#10;&lt;strong&gt;IT業界での意味&lt;/strong&gt;: 製品・サービスの段階的廃止・終了&lt;br&gt;&#10;&lt;strong&gt;語感&lt;/strong&gt;: 急激な「kill」「terminate」ではなく、美しく自然な終わりのイメージ&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: The popular service will be sunset next year due to changing market conditions.&lt;/p&gt;&#10;&lt;h3 id="2-out-of-the-box-performance---初期設定での性能"&gt;2. out-of-the-box performance - 初期設定での性能&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本的意味&lt;/strong&gt;: 箱から出したそのまま&lt;br&gt;&#10;&lt;strong&gt;IT文脈&lt;/strong&gt;: 特別な設定やチューニングなしでの性能&lt;br&gt;&#10;&lt;strong&gt;ニュアンス&lt;/strong&gt;: 「面倒な設定不要で最初からこんなに優秀」という驚きと称賛&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: This software delivers impressive out-of-the-box performance for data analysis.&lt;/p&gt;&#10;&lt;h3 id="3-put-out-a-statement---声明を発表"&gt;3. put out a statement - 声明を発表&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本構造&lt;/strong&gt;: put（出す）+ out（外に）&lt;br&gt;&#10;&lt;strong&gt;ニュアンス&lt;/strong&gt;: 内部検討から外部公表への転換点、人間味のある表現&lt;br&gt;&#10;&lt;strong&gt;類似表現との違い&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;announced: 一般的な発表&lt;/li&gt;&#10;&lt;li&gt;released: やや機械的&lt;/li&gt;&#10;&lt;li&gt;put out: 感情を持った人たちが外に向けて出した感覚 &lt;strong&gt;例文&lt;/strong&gt;: The company put out a statement addressing the recent security concerns.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="4-rest-assured-that---どうか安心してください"&gt;4. Rest assured that - どうか安心してください&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;文法構造&lt;/strong&gt;: (You) rest assured that&amp;hellip;（命令文の省略形）&lt;br&gt;&#10;&lt;strong&gt;使用場面&lt;/strong&gt;: 悪いニュースの後に不安を和らげる定型表現&lt;br&gt;&#10;&lt;strong&gt;語源&lt;/strong&gt;: 16-17世紀からの古い表現が現代でも企業声明で使用&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: Rest assured that your personal data remains completely secure.&lt;/p&gt;&#10;&lt;h3 id="5-chopping-block---廃止候補リスト"&gt;5. chopping-block - 廃止候補リスト&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本的意味&lt;/strong&gt;: まな板、処刑台&lt;br&gt;&#10;&lt;strong&gt;慣用表現&lt;/strong&gt;: on the chopping-block = 廃止候補になった&lt;br&gt;&#10;&lt;strong&gt;イメージ&lt;/strong&gt;: 何かが「切られる運命」にある状態&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: Several legacy systems are on the chopping-block as part of modernization efforts.&lt;/p&gt;&#10;&lt;h3 id="6-upstreamit専門用語--本家への統合"&gt;6. upstream（IT専門用語）- 本家への統合&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本的意味&lt;/strong&gt;: 上流&lt;br&gt;&#10;&lt;strong&gt;IT文脈&lt;/strong&gt;: 独自開発を本家・メインブランチに統合すること&lt;br&gt;&#10;&lt;strong&gt;プロセス&lt;/strong&gt;: 独自最適化 → upstream → 全ユーザーに恩恵&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: Our patches were successfully upstreamed to the main Linux kernel.&lt;/p&gt;&#10;&lt;h3 id="7-ramp-up---段階的強化拡大"&gt;7. ramp up - 段階的強化・拡大&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本イメージ&lt;/strong&gt;: スロープを上るように徐々に規模拡大&lt;br&gt;&#10;&lt;strong&gt;ビジネス用法&lt;/strong&gt;: 計画的・組織的な強化プロセス&lt;br&gt;&#10;&lt;strong&gt;類似語との違い&lt;/strong&gt;: 単なるincreaseより戦略的なニュアンス&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: The team will ramp up production capacity over the next quarter.&lt;/p&gt;&#10;&lt;h3 id="8-cap-off---締めくくる皮肉な文脈で"&gt;8. cap off - 締めくくる（皮肉な文脈で）&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本イメージ&lt;/strong&gt;: 蓋をして仕上げる&lt;br&gt;&#10;&lt;strong&gt;特殊用法&lt;/strong&gt;: 悪い出来事の連続の最後を飾る（皮肉的）&lt;br&gt;&#10;&lt;strong&gt;ニュアンス&lt;/strong&gt;: 「これでもかという悪いニュース」で完璧に締めくくられた&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: The server crash capped off a week of technical difficulties.&lt;/p&gt;&#10;&lt;h3 id="9-orphanedit用語--保守者不在"&gt;9. orphaned（IT用語）- 保守者不在&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;基本的意味&lt;/strong&gt;: 孤児にされた&lt;br&gt;&#10;&lt;strong&gt;IT文脈&lt;/strong&gt;: 担当者がいなくなったコード・ドライバ&lt;br&gt;&#10;&lt;strong&gt;深刻度&lt;/strong&gt;: システムの安定性に関わる重要な問題&lt;br&gt;&#10;&lt;strong&gt;例文&lt;/strong&gt;: The critical library became orphaned after the lead developer left.&lt;/p&gt;&#10;&lt;h3 id="10-let-go---解雇婉曲表現"&gt;10. let go - 解雇（婉曲表現）&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;語感の違い&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;fired: クビ（厳しい印象）&lt;/li&gt;&#10;&lt;li&gt;laid off: 一時解雇（経済的理由）&lt;/li&gt;&#10;&lt;li&gt;let go: 手放した（やむを得ない感じ） &lt;strong&gt;例文&lt;/strong&gt;: Several talented engineers were let go during the recent restructuring.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="文法ポイント学習"&gt;文法ポイント学習&#10;&lt;/h2&gt;&lt;h3 id="1-名詞句主体の感謝表現"&gt;1. 名詞句主体の感謝表現&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;構造&lt;/strong&gt;: A heartfelt thank you to every developer, user, and contributor&amp;hellip;&lt;br&gt;&#10;&lt;strong&gt;特徴&lt;/strong&gt;: 動詞なしで完結する美しい構造&lt;br&gt;&#10;&lt;strong&gt;類似例&lt;/strong&gt;: Best wishes to the graduating class&lt;br&gt;&#10;&lt;strong&gt;日本語との共通点&lt;/strong&gt;: 「心からの感謝を」で余韻を残す修辞法&lt;/p&gt;&#10;&lt;h3 id="2-as-well-による思考プロセスの表現"&gt;2. as well による思考プロセスの表現&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;with as well&lt;/strong&gt;: 思いついたことを列挙している自然さ&lt;br&gt;&#10;&lt;strong&gt;without as well&lt;/strong&gt;: 整理された明確な理由として並列提示&lt;br&gt;&#10;&lt;strong&gt;効果&lt;/strong&gt;: 文章に人間味と信頼性を与える&lt;/p&gt;&#10;&lt;h3 id="3-though-の文中挿入"&gt;3. though の文中挿入&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Today though it&amp;rsquo;s finally been made official&lt;/strong&gt;&lt;br&gt;&#10;&lt;strong&gt;機能&lt;/strong&gt;: 「噂が現実になってしまった」という感情的響き&lt;br&gt;&#10;&lt;strong&gt;位置&lt;/strong&gt;: 文中に挟まれることで口語的・感情的ニュアンス&lt;br&gt;&#10;&lt;strong&gt;効果&lt;/strong&gt;: 記者の個人的感慨を表現&lt;/p&gt;&#10;&lt;h3 id="4-複合主語構造"&gt;4. 複合主語構造&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;those details and whether they will be ramping up those efforts or not remain unclear&lt;/strong&gt;&lt;br&gt;&#10;&lt;strong&gt;構造&lt;/strong&gt;: [名詞] and [whether節] が並列して主語&lt;br&gt;&#10;&lt;strong&gt;動詞&lt;/strong&gt;: remain（複数扱い）&lt;br&gt;&#10;&lt;strong&gt;注意点&lt;/strong&gt;: whether節も名詞節として主語になる&lt;/p&gt;&#10;&lt;h3 id="5-over-の多様な意味展開"&gt;5. over の多様な意味展開&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;俯瞰・期間&lt;/strong&gt;: over the last 10 years（期間全体を俯瞰）&lt;br&gt;&#10;&lt;strong&gt;原因・理由&lt;/strong&gt;: orphaned over departure（退職が原因で）&lt;br&gt;&#10;&lt;strong&gt;共通基盤&lt;/strong&gt;: 「上にある」から派生した抽象概念&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="学習の気づき"&gt;学習の気づき&#10;&lt;/h2&gt;&lt;h3 id="実用英語の特徴"&gt;実用英語の特徴&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;感情表現の豊富さ&lt;/strong&gt;: sunset、put out、let goなど、同じ意味でも語感で使い分け&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;業界特有表現&lt;/strong&gt;: upstream、orphaned、ramp upなど専門文脈での意味変化&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;文体の人間味&lt;/strong&gt;: as well、thoughの挿入で自然な思考プロセスを表現&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;古い表現の生存&lt;/strong&gt;: Rest assured など16世紀からの表現が現代企業声明に&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="受験英語との違い"&gt;受験英語との違い&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;単語の辞書的意味より文脈的ニュアンスが重要&lt;/li&gt;&#10;&lt;li&gt;文法より「なぜその表現を選ぶか」の感覚が大切&lt;/li&gt;&#10;&lt;li&gt;定型表現を分解せず、塊として理解する必要性&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="複合的理解の解決手法"&gt;複合的理解の解決手法&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;要素分解&lt;/strong&gt;: 複数の未知要素を一つずつ分解&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;文脈判断&lt;/strong&gt;: 業界・場面特有の用法を考慮&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;語感重視&lt;/strong&gt;: 同義語間の微妙なニュアンス差を理解&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;構造分析&lt;/strong&gt;: 複雑な文法構造を段階的に解析&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="復習用例文"&gt;復習用例文&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;The legacy system will be sunset next year, but rest assured that all data will be migrated safely.&lt;/strong&gt; （レガシーシステムは来年廃止されますが、全データは安全に移行されますのでご安心ください）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;We&amp;rsquo;re ramping up our development efforts and getting more features upstreamed as well.&lt;/strong&gt; （開発努力を強化しており、より多くの機能を本家にも統合してもらっています）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;The project became orphaned over the team lead&amp;rsquo;s departure, which capped off a difficult quarter.&lt;/strong&gt; （チームリーダーの退職でプロジェクトが保守者不在となり、困難な四半期が締めくくられました）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;This software delivers impressive out-of-the-box performance, so users don&amp;rsquo;t need complex configuration.&lt;/strong&gt; （このソフトウェアは初期設定で素晴らしい性能を発揮するので、複雑な設定は不要です）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Several engineers were let go as part of the restructuring, though the company put out a statement emphasizing continued Linux support.&lt;/strong&gt; （リストラの一環で数名のエンジニアが解雇されましたが、会社はLinux支援継続を強調する声明を発表しました）&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="今後の学習方針"&gt;今後の学習方針&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;業界特有表現の蓄積&lt;/strong&gt;: 技術記事での専門用語の実用的意味を重点学習&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;感情表現の習得&lt;/strong&gt;: 同義語の語感・ニュアンス差の理解を深化&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;文体判断力向上&lt;/strong&gt;: フォーマル/カジュアル、口語/書面語の使い分け感覚育成&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;複合困難対処&lt;/strong&gt;: 複数要素が重なった場合の段階的分解技術向上&lt;/li&gt;&#10;&lt;/ol&gt;&#10;</description></item><item><title>RSSの現状と将来性：20年スパンの包括的分析</title><link>https://ai.hack-le.com/rss%E3%81%AE%E7%8F%BE%E7%8A%B6%E3%81%A8%E5%B0%86%E6%9D%A5%E6%80%A7%EF%BC%9A20%E5%B9%B4%E3%82%B9%E3%83%91%E3%83%B3%E3%81%AE%E5%8C%85%E6%8B%AC%E7%9A%84%E5%88%86%E6%9E%90/</link><pubDate>Wed, 23 Jul 2025 12:52:44 +0900</pubDate><guid>https://ai.hack-le.com/rss%E3%81%AE%E7%8F%BE%E7%8A%B6%E3%81%A8%E5%B0%86%E6%9D%A5%E6%80%A7%EF%BC%9A20%E5%B9%B4%E3%82%B9%E3%83%91%E3%83%B3%E3%81%AE%E5%8C%85%E6%8B%AC%E7%9A%84%E5%88%86%E6%9E%90/</guid><description>&lt;p&gt;RSS（Really Simple Syndication）は2000年代のピーク時から&lt;strong&gt;90%の利用者減少&lt;/strong&gt;を経験したが、特定分野では持続的成長を示している。日本市場は&lt;strong&gt;グローバル企業利用の52.4%&lt;/strong&gt; を占め、世界最大のRSS活用地域となっている。データが示すのは、主流から専門領域への技術転換と、プライバシー重視の現代における静かな復権である。&lt;/p&gt;&#10;&lt;h2 id="利用者数の歴史的推移栄光と衰退の数値記録"&gt;利用者数の歴史的推移：栄光と衰退の数値記録&#10;&lt;/h2&gt;&lt;h3 id="ピーク期の定量的実態2005-2010年"&gt;ピーク期の定量的実態（2005-2010年）&#10;&lt;/h3&gt;&lt;p&gt;2006年のMarketingSherpa調査が示すRSSブームの実態は、&lt;strong&gt;米英合計7,500万人の定期利用者&lt;/strong&gt;という規模だった。しかし利用者の67%（5,000万人）は&lt;strong&gt;自分がRSS技術を使用していることを認識していなかった&lt;/strong&gt;。この数値は、RSS普及の表面的成功と根本的課題を同時に物語る。&lt;/p&gt;&#10;&lt;p&gt;技術仕様別では&lt;strong&gt;RSS 2.0が67%、RSS 1.0が17%、RSS 0.91が13%&lt;/strong&gt; のシェアを占め、WordPressの普及とともにRSS 2.0が事実上の標準となった。この時期、&lt;strong&gt;34.41%のニューヨーク州学術図書館&lt;/strong&gt;がRSSを含むWeb 2.0サービスを導入し、専門機関での組織的採用が進んでいた。&lt;/p&gt;&#10;&lt;h3 id="google-reader時代の中央集権化2005-2013年"&gt;Google Reader時代の中央集権化（2005-2013年）&#10;&lt;/h3&gt;&lt;p&gt;Google Readerは&lt;strong&gt;月間100万アクティブユーザー&lt;/strong&gt;を抱え、RSS生態系の中核となった。TechCrunchへの流入分析では、Google Readerが&lt;strong&gt;第4位の流入源&lt;/strong&gt;（Google検索、Facebook、Twitterに次ぐ）で、&lt;strong&gt;30日間で全訪問の3%を占めた。2010年のピーク時には2013年の3倍のトラフィック&lt;/strong&gt;を生み出していたが、これがRSS衰退の前兆でもあった。&lt;/p&gt;&#10;&lt;h3 id="大移民とエコシステム再編2013年"&gt;大移民とエコシステム再編（2013年）&#10;&lt;/h3&gt;&lt;p&gt;2013年3月のGoogle Reader終了発表は、&lt;strong&gt;48時間でFeedlyに50万新規ユーザー&lt;/strong&gt;、&lt;strong&gt;2週間で300万ユーザー&lt;/strong&gt;の流入を生んだ。NewsBlurは&lt;strong&gt;1,500から60,000ユーザー&lt;/strong&gt;へ急拡大し、Change.orgの存続嘆願には&lt;strong&gt;10万筆以上&lt;/strong&gt;の署名が集まった。この数値は、RSS利用者の組織的移行能力と技術への執着を証明している。&lt;/p&gt;&#10;&lt;h3 id="現在の利用状況専門化された生存"&gt;現在の利用状況：専門化された生存&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;現在の推定利用者数は2,000-3,000万人&lt;/strong&gt;で、ピーク時の75%減となった。しかし質的変化は注目に値する。&lt;strong&gt;Feedlyは1,500万登録ユーザー&lt;/strong&gt;を抱え、&lt;strong&gt;6万のPro契約者&lt;/strong&gt;が月額8ドルを支払う。企業利用では&lt;strong&gt;世界6,457社&lt;/strong&gt;がFeedlyを導入し、内訳は&lt;strong&gt;日本3,039社（52.42%）、米国1,694社（29.22%）、英国198社（3.42%）&lt;/strong&gt; となる。&lt;/p&gt;&#10;&lt;h2 id="日本市場の特異性世界最大のrss活用地域"&gt;日本市場の特異性：世界最大のRSS活用地域&#10;&lt;/h2&gt;&lt;h3 id="日本メディアの高rss対応率"&gt;日本メディアの高RSS対応率&#10;&lt;/h3&gt;&lt;p&gt;日本の主要メディアは&lt;strong&gt;85-90%のRSS対応率&lt;/strong&gt;を示し、グローバル平均の70-80%を上回る。&lt;strong&gt;NHK、朝日新聞、日経アジア、毎日新聞、共同通信&lt;/strong&gt;が包括的RSS配信を継続し、&lt;strong&gt;首相官邸、国立国会図書館&lt;/strong&gt;も公式RSS配信を行う。この組織的対応は、情報の系統的配信を重視する日本の文化的特性を反映している。&lt;/p&gt;&#10;&lt;h3 id="企業利用における日本の突出"&gt;企業利用における日本の突出&#10;&lt;/h3&gt;&lt;p&gt;グローバル企業RSS利用の&lt;strong&gt;52.4%を日本が占める&lt;/strong&gt;事実は、日本市場の特異性を示す最重要指標である。これは単純な人口比（世界の1.6%）を大幅に上回り、&lt;strong&gt;32.5倍の集中度&lt;/strong&gt;を示している。政府機関のRSS対応、企業の系統的情報収集文化、SNS疲れへの反発が複合的要因と推測される。&lt;/p&gt;&#10;&lt;h3 id="技術採用パターンの違い"&gt;技術採用パターンの違い&#10;&lt;/h3&gt;&lt;p&gt;日本市場では&lt;strong&gt;国際サービス（Feedly、Inoreader）への依存&lt;/strong&gt;が顕著で、独自RSS開発は2006年のライブドア・リーダー以降停滞している。しかし利用率の高さは、技術への適応力よりも情報管理手法への価値観の違いを反映している。&lt;/p&gt;&#10;&lt;h2 id="rssサービス市場の現実的評価"&gt;RSSサービス市場の現実的評価&#10;&lt;/h2&gt;&lt;h3 id="収益モデルの成熟化"&gt;収益モデルの成熟化&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Feedlyの2015年Pro契約者5万人から現在6万人&lt;/strong&gt;への成長は年率1.9%の安定拡大を示す。&lt;strong&gt;プレミアム料金月額7-12ドル&lt;/strong&gt;の価格帯で、推定&lt;strong&gt;年間売上数百万ドル規模&lt;/strong&gt;の市場が形成されている。これは縮小した利用者基盤でも&lt;strong&gt;高付加価値サービス&lt;/strong&gt;として持続可能性を証明している。&lt;/p&gt;&#10;&lt;h3 id="オープンソース開発の活発さ"&gt;オープンソース開発の活発さ&#10;&lt;/h3&gt;&lt;p&gt;GitHub上のRSS関連プロジェクトは&lt;strong&gt;活発な開発継続&lt;/strong&gt;を示す。&lt;strong&gt;NetNewsWireが8.8K GitHub stars&lt;/strong&gt;、&lt;strong&gt;FreshRSS、Miniflux&lt;/strong&gt;等のセルフホスト型ソリューションが成長し、プライバシー重視ユーザーの受け皿となっている。開発者コミュニティの&lt;strong&gt;技術的信念に基づく継続的投資&lt;/strong&gt;が、商業的成功とは別の持続基盤を提供している。&lt;/p&gt;&#10;&lt;h3 id="ブラウザ対応の系統的撤退"&gt;ブラウザ対応の系統的撤退&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Firefox（2011年）、Safari（2012年）、Chrome（対応せず）&lt;/strong&gt; のRSS機能撤廃は、一般利用者のRSS発見経路を断絶させた。&lt;strong&gt;Firefox統計では利用率0.01%&lt;/strong&gt; という低迷が撤廃理由とされ、技術的優位性と利用実態の乖離を示している。&lt;/p&gt;&#10;&lt;h2 id="メディアパブリッシャーのrss戦略分析"&gt;メディア・パブリッシャーのRSS戦略分析&#10;&lt;/h2&gt;&lt;h3 id="大手メディアの持続的対応"&gt;大手メディアの持続的対応&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;CNN、BBC、ニューヨーク・タイムズ、ワシントン・ポスト、AP通信、ロイター&lt;/strong&gt;等の主要国際メディアは&lt;strong&gt;包括的RSS配信を継続&lt;/strong&gt;している。これは専門読者層への配慮と、&lt;strong&gt;RSS経由利用者の高エンゲージメント率&lt;/strong&gt;（セッション時間長、回遊率高）を評価した戦略判断である。&lt;/p&gt;&#10;&lt;h3 id="ソーシャルメディアの戦略転換"&gt;ソーシャルメディアの戦略転換&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Twitter（2013年3月）、Facebook（2012年）のRSS配信停止は、利用者をプラットフォーム内に囲い込む戦略転換を示す。特にTwitterはapi.twitter.com/1/statuses/user_timeline.rss&lt;/strong&gt;から完全撤廃し、サードパーティRSSサービスへの依存を強制した。これは情報配信の&lt;strong&gt;中央集権化戦略&lt;/strong&gt;の明確な表明である。&lt;/p&gt;&#10;&lt;h3 id="wordpress生態系の基盤的役割"&gt;WordPress生態系の基盤的役割&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;全ウェブサイトの43%を占めるWordPress&lt;/strong&gt;が&lt;strong&gt;標準RSS対応&lt;/strong&gt;（/feed URL構造）を維持していることは、RSS技術の生存基盤となっている。&lt;strong&gt;95%のWordPressサイト&lt;/strong&gt;でRSSが利用可能で、この技術的普遍性がRSS完全消滅を防いでいる。&lt;/p&gt;&#10;&lt;h2 id="技術進化と現代的位置づけ"&gt;技術進化と現代的位置づけ&#10;&lt;/h2&gt;&lt;h3 id="ai統合の本格化"&gt;AI統合の本格化&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;2024-2025年のRSS + AI統合&lt;/strong&gt;は実用段階に達している。&lt;strong&gt;コンテンツ要約、自動分類、パーソナライゼーション&lt;/strong&gt;機能を持つRSSリーダーが登場し、&lt;strong&gt;6桁収入規模&lt;/strong&gt;のAI駆動コンテンツキュレーション事業も生まれている。&lt;strong&gt;Microsoft Teams、Slack統合&lt;/strong&gt;により企業ワークフローへの組み込みが進む。&lt;/p&gt;&#10;&lt;h3 id="web3分散化ウェブとの連携"&gt;Web3・分散化ウェブとの連携&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;RSS3プロトコル&lt;/strong&gt;が&lt;strong&gt;月間4億リクエストのRSSHub&lt;/strong&gt;と連携し、ブロックチェーン基盤の情報配信システムを構築中である。&lt;strong&gt;ウォレットベースID、DeFiプロトコル統合&lt;/strong&gt;等の技術革新により、従来の中央集権的情報配信への代替を目指している。ただし&lt;strong&gt;暗号資産ウォレットの複雑さ&lt;/strong&gt;が一般普及の障壁となっている。&lt;/p&gt;&#10;&lt;h3 id="プライバシー保護の再評価"&gt;プライバシー保護の再評価&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;アルゴリズム疲れ、追跡拒否&lt;/strong&gt;の文脈で、RSSが&lt;strong&gt;匿名情報消費、時系列順表示&lt;/strong&gt;の価値を再評価されている。Dave Winer（RSS開発者）の2024年発言「&lt;strong&gt;RSSは人々が存在を望むから存在する&lt;/strong&gt;」は、技術的優位性より哲学的価値への転換を示唆する。&lt;/p&gt;&#10;&lt;h2 id="定量的予測と将来シナリオ"&gt;定量的予測と将来シナリオ&#10;&lt;/h2&gt;&lt;h3 id="現実的成長予測2025-2030年"&gt;現実的成長予測（2025-2030年）&#10;&lt;/h3&gt;&lt;p&gt;現在の&lt;strong&gt;年間2-3%安定成長&lt;/strong&gt;傾向に基づくと、2030年のRSS利用者数は&lt;strong&gt;3,300-3,500万人&lt;/strong&gt;と予測される。これは&lt;strong&gt;指数的復活ではなく、専門用途の着実拡大&lt;/strong&gt;を意味する。企業利用の&lt;strong&gt;日本集中傾向&lt;/strong&gt;が継続すれば、日本が&lt;strong&gt;グローバルRSS利用の60%&lt;/strong&gt; を占める可能性もある。&lt;/p&gt;&#10;&lt;h3 id="市場規模の経済分析"&gt;市場規模の経済分析&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Feedlyの年間売上数百万ドル、Inoreaderの安定収益&lt;/strong&gt;等から、&lt;strong&gt;グローバルRSS市場規模を年間1,000-2,000万ドル&lt;/strong&gt;と推定できる。これはTwitter（現X）の&lt;strong&gt;年間50億ドル売上&lt;/strong&gt;の0.2-0.4%に過ぎないが、&lt;strong&gt;利益率の高いニッチ市場&lt;/strong&gt;として持続可能である。&lt;/p&gt;&#10;&lt;h3 id="シナリオ別将来予測"&gt;シナリオ別将来予測&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;楽観シナリオ（30%確率）&lt;/strong&gt; : AI統合とプライバシー重視により年間5-7%成長、2030年5,000万ユーザー &lt;strong&gt;基調シナリオ（50%確率）&lt;/strong&gt; : 現状維持的拡大で年間2-3%成長、2030年3,500万ユーザー&lt;br&gt;&#10;&lt;strong&gt;悲観シナリオ（20%確率）&lt;/strong&gt; : 技術的陳腐化により年間-1%縮小、2030年2,500万ユーザー&lt;/p&gt;&#10;&lt;h2 id="rss本質価値の現代的再評価"&gt;RSS本質価値の現代的再評価&#10;&lt;/h2&gt;&lt;h3 id="アルゴリズム支配への対抗手段"&gt;アルゴリズム支配への対抗手段&#10;&lt;/h3&gt;&lt;p&gt;「&lt;strong&gt;サービス側による恣意的情報選択&lt;/strong&gt;」への懸念が高まる中、RSSの「&lt;strong&gt;選択したソースからの時系列愚直受信&lt;/strong&gt;」は新たな価値を獲得している。しかし&lt;strong&gt;一般利用者の復帰&lt;/strong&gt;は数値的に確認できない。価値認識と実際利用の間には&lt;strong&gt;認知コストと利便性の壁&lt;/strong&gt;が存在する。&lt;/p&gt;&#10;&lt;h3 id="専門職における不可欠ツール化"&gt;専門職における不可欠ツール化&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ジャーナリスト、研究者、開発者&lt;/strong&gt;等の情報専門職では&lt;strong&gt;RSS利用率70%以上&lt;/strong&gt;を示す調査もあり、&lt;strong&gt;職業的必需品&lt;/strong&gt;として確立している。この「&lt;strong&gt;プロフェッショナル・ツール化&lt;/strong&gt;」こそが、RSSの現実的生存戦略である。&lt;/p&gt;&#10;&lt;h2 id="結論データが示す冷徹な現実と持続的価値"&gt;結論：データが示す冷徹な現実と持続的価値&#10;&lt;/h2&gt;&lt;p&gt;RSS技術は&lt;strong&gt;主流復帰の幻想を捨て、専門分野での確固たる地位を築いた&lt;/strong&gt;。&lt;strong&gt;7,500万から3,000万への利用者減少&lt;/strong&gt;は事実だが、&lt;strong&gt;企業6,457社の導入、年間数千万ドルの市場規模、活発な技術開発&lt;/strong&gt;が持続性を証明する。&lt;/p&gt;&#10;&lt;p&gt;日本市場の&lt;strong&gt;52.4%集中&lt;/strong&gt;は偶然ではなく、情報管理文化と技術受容性の&lt;strong&gt;構造的優位性&lt;/strong&gt;を示す。&lt;strong&gt;政府機関RSS対応、メディア85%対応率、企業組織的導入&lt;/strong&gt;等、日本はRSS活用の&lt;strong&gt;世界標準モデル&lt;/strong&gt;となっている。&lt;/p&gt;&#10;&lt;p&gt;「ロートル扱い」への反証は数値に現れている。&lt;strong&gt;GitHub開発活動、AI統合進展、企業ワークフロー組み込み&lt;/strong&gt;等、RSSは&lt;strong&gt;過去の技術ではなく現在進行形の基盤インフラ&lt;/strong&gt;である。ただし&lt;strong&gt;一般消費者市場への復帰は非現実的&lt;/strong&gt;で、&lt;strong&gt;専門用途特化&lt;/strong&gt;こそが持続的発展戦略となる。&lt;/p&gt;&#10;&lt;p&gt;RSSの未来は&lt;strong&gt;大衆的復権ではなく、情報専門職の必需品として、AI時代の基盤技術として、分散型ウェブの構成要素として&lt;/strong&gt;の地位確立にある。これは衰退ではなく、&lt;strong&gt;技術成熟による適正規模への収斂&lt;/strong&gt;と評価すべきである。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://ai.hack-le.com/images/uploads/2025/07/RSSs-Evolution_-Comprehensive-20-Year-Analysis-of-Decline-and-Specialized-Growth.pdf" &gt;RSS&amp;rsquo;s Evolution_ Comprehensive 20-Year Analysis of Decline and Specialized Growth (PDF)&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Waylandの批判と実態: 2025年のLinuxデスクトップ環境における包括的調査</title><link>https://ai.hack-le.com/wayland%E3%81%AE%E6%89%B9%E5%88%A4%E3%81%A8%E5%AE%9F%E6%85%8B-2025%E5%B9%B4%E3%81%AElinux%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E7%92%B0%E5%A2%83%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B/</link><pubDate>Mon, 21 Jul 2025 07:36:59 +0900</pubDate><guid>https://ai.hack-le.com/wayland%E3%81%AE%E6%89%B9%E5%88%A4%E3%81%A8%E5%AE%9F%E6%85%8B-2025%E5%B9%B4%E3%81%AElinux%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E7%92%B0%E5%A2%83%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B/</guid><description>&lt;p&gt;Waylandは2024-2025年において重要な転換点を迎えているが、技術的成熟と実用性の間には依然として大きなギャップが存在する。主要ディストリビューションがWaylandをデフォルトにする一方で、開発者や専門ユーザーからの根本的な批判は継続しており、多くの基本的なデスクトップ機能が未だに制限されている状況にある。&lt;/p&gt;&#10;&lt;h2 id="ubuntu中心の主要ディストリビューション対応状況"&gt;Ubuntu中心の主要ディストリビューション対応状況&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Ubuntuの移行タイムライン&lt;/strong&gt;では、2017年のUbuntu 17.10でWaylandをデフォルトにしたものの、安定性の問題で18.04では即座にX11に戻した歴史がある。2021年のUbuntu 21.04で再びWaylandをデフォルトに設定したが、NVIDIAユーザーについては&lt;strong&gt;AI/ML、VFXなどの産業での重要性&lt;/strong&gt;を理由に24.04 LTSでもX11を維持していた。しかし&lt;strong&gt;2024年10月のUbuntu 24.10&lt;/strong&gt;でついにNVIDIAユーザーでもWaylandがデフォルトとなり、2025年予定の25.10では完全なWayland移行が計画されている。&lt;/p&gt;&#10;&lt;p&gt;Fedoraは&lt;strong&gt;2016年からWayland採用の先駆者&lt;/strong&gt;として、2024年のFedora 41でGNOME X11セッションをインストールメディアから削除し、&lt;strong&gt;2025年のFedora 43では完全にWaylandのみ&lt;/strong&gt;となる予定だ。Red Hat Enterprise Linux（RHEL）では&lt;strong&gt;2025年前半リリース予定のRHEL 10でXorgサーバーを完全に削除&lt;/strong&gt;する決定を下しており、これは企業向けLinux最大手がWaylandに完全移行することを意味する重要な転換点となっている。&lt;/p&gt;&#10;&lt;p&gt;KDE Plasma 6では&lt;strong&gt;Waylandがデフォルトセッションとなり機能パリティを達成&lt;/strong&gt;したとされ、現在70-80%のユーザーがWaylandを使用している。一方、XfceのWayland対応は2024年12月のXfce 4.20で実験的サポートが開始されたばかりで、CinnamonもLinux Mint 23.xで2026年に本格対応予定と、デスクトップ環境によって対応状況に大きな差がある。&lt;/p&gt;&#10;&lt;h2 id="開発者からの根本的批判と技術的課題"&gt;開発者からの根本的批判と技術的課題&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;APIの複雑さと設計哲学の問題&lt;/strong&gt;については、開発者コミュニティから痛烈な批判が寄せられている。特に2025年にKiCadチームが発表したブログ記事では、Waylandの設計が基本的なデスクトップアプリケーション機能を&lt;strong&gt;意図的に除外している&lt;/strong&gt;ことを厳しく批判している。「ウィンドウの配置、マウスカーソルの移動、グローバルショートカットなど、X11、Windows、macOSで何十年も使われてきた基本機能が設計上除外されている」と指摘し、KiCadは&lt;strong&gt;Wayland関連のバグレポートを調査・サポートしない&lt;/strong&gt;という明確な方針を表明している。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;プロトコルの断片化&lt;/strong&gt;も深刻な問題となっている。X11の統一されたXorgサーバーとは異なり、WaylandにはGNOME/Mutter、KDE/KWin、wlroots系コンポジター、Westonなど複数の実装があり、&lt;strong&gt;それぞれが異なる方法でプロトコルを解釈&lt;/strong&gt;している。mpv開発者は「全く正当で完全に正しいWaylandコードが、他のコンポジターでは突然動かなくなることが十分にあり得る」と述べ、開発者が4つの異なるWayland実装（Mutter、Plasma、wlroots、Weston）をサポートしなければならない状況を批判している。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;X11からの移植コストと開発ドキュメントの問題&lt;/strong&gt;については、「Waylandクライアントプログラミングガイドでは、ドキュメントが完全にコードと同期しておらず、ネット上で見つかる例は動作せず、動作させるのは最低でも困難」と記されている状況だ。14年の開発期間を経ても、&lt;strong&gt;プログラミング書籍が出版されていない&lt;/strong&gt;のは、技術の成熟度を如実に表している。&lt;/p&gt;&#10;&lt;h2 id="nvidiaドライバー対応状況と具体的問題"&gt;NVIDIAドライバー対応状況と具体的問題&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;NVIDIAドライバーのWayland対応&lt;/strong&gt;は2024年に大きな転換点を迎えた。&lt;strong&gt;NVIDIA 555シリーズ&lt;/strong&gt;で念願のexplicit sync対応が実現し、長年の問題だった画面のちらつきや黒い画面、視覚的な不具合が大幅に改善された。現在はNVIDIA 495以降でWaylandの基本サポートが提供されており、560以降ではnvidia-drm modeset=1がデフォルトで有効になっている。&lt;/p&gt;&#10;&lt;p&gt;しかし、&lt;strong&gt;ゲーミング性能に関する問題は継続&lt;/strong&gt;している。Steam Playでのプロトンゲームでは60%以上のパフォーマンス低下が報告され、Unity エンジンゲームではCPU描画のような極度に悪いパフォーマンスが発生する。Baldur&amp;rsquo;s Gate 3では&lt;strong&gt;GPU クラッシュとピクセル化した灰色の四角&lt;/strong&gt;が表示され、Helldivers 2ではフレーム低下とシステム不安定が頻発している。特にOptimus（ハイブリッドグラフィックス）搭載ラップトップでは&lt;strong&gt;外部モニター取り外し時にクラッシュ&lt;/strong&gt;が発生し、マルチモニター構成での不安定性が指摘されている。&lt;/p&gt;&#10;&lt;p&gt;AMD とIntelのグラフィックスドライバーはWaylandで&lt;strong&gt;優秀な互換性&lt;/strong&gt;を提供しており、多くの場合X11よりも優れたパフォーマンスを示している。特にIntelは&lt;strong&gt;最高級のWaylandサポート&lt;/strong&gt;を提供すると評価され、Linux カーネルやグラフィックススタックへの貢献も大きい。しかし、&lt;strong&gt;4K動画再生テスト&lt;/strong&gt;では、Waylandが12.54%のCPU使用率を記録したのに対し、X11（コンポジティング無効）では3.6%と、Waylandで18%のパフォーマンス低下が確認されている。&lt;/p&gt;&#10;&lt;h2 id="キーボード入力システムと基本デスクトップ機能の課題"&gt;キーボード入力システムと基本デスクトップ機能の課題&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;日本語入力（IME）の問題&lt;/strong&gt;は特に深刻で、Waylandの入力メソッドアーキテクチャーには&lt;strong&gt;深刻なプロトコル断片化&lt;/strong&gt;が存在する。text-input プロトコル（v1、v2、v3）とinput-method プロトコル（v1、v2）がすべて&lt;strong&gt;完全に非互換&lt;/strong&gt;で、アプリケーション、ディスプレイサーバー、入力メソッド間のプロトコルバージョンが完全に一致しなければ、多言語テキスト入力が&lt;strong&gt;完全に失敗&lt;/strong&gt;する。Mozc日本語入力はZorin OS 17などのディストリビューションでWaylandセッションでの動作に失敗し、X11に切り替えた場合のみ正常に動作するという報告が多数ある。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;グローバルショートカット機能&lt;/strong&gt;は基本的に破綻している状況で、GNOME とwlroots系コンポジターはglobal shortcuts desktop portalをサポートしておらず、&lt;strong&gt;KDE Plasmaのみが動作する実装を提供&lt;/strong&gt;している。Hyprlandの実装は「ほとんど無用」と評される状態で、アプリケーションが提供するデフォルトホットキーを無視し、GUIによるホットキー管理も存在せず、手動で設定ファイルの編集が必要となっている。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;リモートデスクトップ（VNC、RDP）の互換性問題&lt;/strong&gt;では、X11の標準だった&lt;strong&gt;x11vncの同等品が存在しない&lt;/strong&gt;状況が続いている。WayVNCはwlroots系コンポジターでのみ動作し、gnome-remote-desktopは&lt;strong&gt;帯域幅要求が10倍以上&lt;/strong&gt;（1-2 Mbps → 10+ Mbps）となり、低速接続でのリモートワークが実質不可能になっている。KDE のKRdpは不安定でクラッシュが頻発し、既存のVNCベースの企業インフラが使用できなくなるため、&lt;strong&gt;企業のWayland移行が阻害&lt;/strong&gt;されている。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;スクリーンキャプチャと録画ソフトウェアの制限&lt;/strong&gt;も深刻で、OBS Studioでは複雑な環境変数設定とportal依存性が必要で、多くの場合黒い背景にカーソルのみが表示される問題が発生している。Screenshot ツールのSpectacle（KDE）では「スクリーンショットを撮ることができませんでした」エラーが頻発し、Flameshotではクリップボードへのコピー機能が&lt;strong&gt;完全に破損&lt;/strong&gt;している。&lt;/p&gt;&#10;&lt;h2 id="エンドユーザーの実際の使用感と深刻な不満"&gt;エンドユーザーの実際の使用感と深刻な不満&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;システム安定性の問題&lt;/strong&gt;では、Ubuntu 22.04ユーザーから「インストール時にWaylandがデフォルトになり、数時間のランダムな周期でシステム全体がハードクラッシュする。セッションをX11に戻すと問題が停止した」という報告が多数寄せられている。Git GUI/Gitkでは「80%の確率でアプリ起動時に破損したインターフェイスが表示され、gitkを数回再起動するとwaylandセッションがクラッシュする」という問題が報告されている。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;プロフェッショナルソフトウェアの互換性&lt;/strong&gt;では、Eclipse IDEが複数バージョンでUbuntu上のWaylandでクラッシュし、&lt;code&gt;GDK_BACKEND=x11&lt;/code&gt;の設定でX11モードを強制する必要がある。XP-Penタブレットユーザーは「waylandではペンを実際に画面に書かせることが不可能」と述べ、WindowsからLinuxへの移行を断念している。AutoKeyによる自動化ツールは&lt;strong&gt;完全に破損&lt;/strong&gt;し、「これはX11アプリケーションであり、Waylandをデフォルトとして使用するディストリビューションでは100%機能しない」と公式に表明されている。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;リモートワークとスクリーン共有の深刻な問題&lt;/strong&gt;では、Zoomで「Screen Shareがwaylandで破損している」という数百の返信があるコミュニティスレッドが継続している。Zoomは「waylandをサポートするのはUbuntu（17、18）、Fedora（25から29）、Debian 9、openSUSE Leap 15、Arch LinuxでのGNOMEのみ」という限定的なプラットフォームサポートしか提供しておらず、「共有を停止したり、他の参加者が何かを共有しようとするたびにアプリが完全にクラッシュするのは致命的」とユーザーは訴えている。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;ゲーミング性能の不満&lt;/strong&gt;では、Arch Linuxユーザーが「Steam FPSカウンターが安定した55-60 FPSを示しているにもかかわらず、ゲームプレイが遅延し、時々スローモーションのように感じられる」と報告している。GNOME Gamesユーザーは「waylandでのgnome-gamesテストでは、ゲームの動作が遅く、音が連続的にカットされるパフォーマンスに顕著な違いが見られる」と述べている。&lt;/p&gt;&#10;&lt;h2 id="最新の改善状況と今後の展望"&gt;最新の改善状況と今後の展望&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;2024年の技術的ブレークスルー&lt;/strong&gt;として、&lt;strong&gt;explicit syncプロトコルの全面展開&lt;/strong&gt;が実現された。Mesa 24.1でのVulkanドライバー対応、KDE Plasma 6.1での完全実装、GNOMEでのMutterへのマージ、NVIDIA 555以降でのドライバー対応、XWaylandでのサポート統合により、&lt;strong&gt;NVIDIAユーザーにとっての主要な障壁が解決&lt;/strong&gt;された。これにより、長年の問題だったちらつき、黒いウィンドウ、グラフィカルアーティファクトが大幅に改善されている。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;カラーマネジメントプロトコル&lt;/strong&gt;も2025年2月にwayland-protocols 1.41として&lt;strong&gt;5年間の開発努力が完結&lt;/strong&gt;し、KWin、Mutter、Weston、wlrootsでの実装が進行中だ。sRGB、Wide Color Gamut（WCG）、HDRコンテンツのサポートを提供し、2025-2026年にエンターテイメント向けHDRサポートが実用化される見込みだ。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;企業の戦略とロードマップ&lt;/strong&gt;では、Red Hat Enterprise Linux 10が2025年前半に&lt;strong&gt;Xorgサーバーを完全削除&lt;/strong&gt;する決定を下し、「RHEL 10からは最新のスタックとエコシステムのみに注力することで、HDR、セキュリティ強化、低・高密度ディスプレイの混在セットアップなどの問題に取り組むことができる」と表明している。Canonicalも&lt;strong&gt;Ubuntu 24.10でNVIDIA Waylandをデフォルト&lt;/strong&gt;にし、企業とデスクトップの融合に投資を継続している。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;アプリケーションエコシステムの改善&lt;/strong&gt;では、JetBrains IDE 2024.2でネイティブWaylandサポートが実装され、Godot 4.3、VirtualBox 7.1、Chrome でのVA-API動画アクセラレーションなど、2024年に多くの重要アプリケーションがWayland対応を完了している。Wine 9.22では&lt;strong&gt;Waylandドライバーがデフォルト有効&lt;/strong&gt;となり、Valve エンジニアがWaylandプロトコル開発を加速している。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;残存する技術的課題&lt;/strong&gt;として、スクリーン録画と共有はportalベースのソリューションが標準化途中で、Discord のネイティブWaylandスクリーン共有が2025年に予定されている。グローバルホットキーはinput capture portalが基盤を提供し、アプリケーション固有のソリューション開発が進行中だ。&lt;strong&gt;レガシーアプリケーションサポート&lt;/strong&gt;ではXWaylandの改善によるX11互換性向上、Wine WaylandドライバーのP成熟、Flatpak/XDG portalの標準化が継続されている。&lt;/p&gt;&#10;&lt;h2 id="結論2025年のwaylandの現実"&gt;結論：2025年のWaylandの現実&#10;&lt;/h2&gt;&lt;p&gt;調査結果から、&lt;strong&gt;Waylandは2024-2025年に重要な技術的転換点を迎えた&lt;/strong&gt;ことが明確になった。explicit syncの実装とNVIDIA互換性の改善、主要デスクトップ環境での機能パリティ達成、企業レベルでのコミットメントにより、メインストリーム用途では「実験的代替手段」から「プロダクション標準」への移行が完了している。&lt;/p&gt;&#10;&lt;p&gt;しかし、&lt;strong&gt;専門的ワークフローと特殊アプリケーション領域では重大な問題が継続&lt;/strong&gt;している。日本語入力システムの不安定性、プロフェッショナルソフトウェアの互換性問題、リモートデスクトップアクセスの制限、基本的なデスクトップユーティリティの欠如など、日常的な生産性に直接影響する問題が多数残存している。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;開発者コミュニティからの根本的批判&lt;/strong&gt;は設計哲学レベルに及び、セキュリティ重視の設計選択と実用的な開発者・ユーザーニーズとの間の根本的緊張関係を示している。KiCadのような専門アプリケーションによる&lt;strong&gt;明示的なWayland拒否&lt;/strong&gt;は、プロトコル制限への対処よりも回避を選択するトレンドを表している。&lt;/p&gt;&#10;&lt;p&gt;2025年以降の展望としては、&lt;strong&gt;企業環境と一般デスクトップ使用では Waylandが主流&lt;/strong&gt;となる一方、&lt;strong&gt;専門的・レガシーワークフローではX11が継続的に必要&lt;/strong&gt;という二極化が進行すると予測される。組織は個別の要件に基づいてWayland移行戦略を慎重に計画し、特に日本語環境やプロフェッショナルツールを多用する環境では段階的な検証アプローチが推奨される。&lt;/p&gt;&#10;&lt;h2 id="pdf"&gt;pdf&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://ai.hack-le.com/images/uploads/2025/07/Waylands-Criticisms-and-Reality_-A-Comprehensive-Assessment-of-Linux-Desktop-Environments-in-2025.pdf" &gt;Wayland&amp;rsquo;s Criticisms and Reality_ A Comprehensive Assessment of Linux Desktop Environments in 2025 (PDF)&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>FreeFileSync寄付版の完全ガイド</title><link>https://ai.hack-le.com/freefilesync%E5%AF%84%E4%BB%98%E7%89%88%E3%81%AE%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89/</link><pubDate>Sun, 20 Jul 2025 17:31:48 +0900</pubDate><guid>https://ai.hack-le.com/freefilesync%E5%AF%84%E4%BB%98%E7%89%88%E3%81%AE%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89/</guid><description>&lt;p&gt;FreeFileSyncの寄付版（Donation Edition）は、&lt;strong&gt;任意の金額で機能強化と開発支援を両立&lt;/strong&gt;できる個人向け追加オプションです。無料版だけでも十分実用的ですが、寄付版では並列処理による大幅な高速化とメンテナンス作業の自動化が実現されます。&lt;/p&gt;&#10;&lt;h2 id="寄付版で追加される核心機能"&gt;寄付版で追加される核心機能&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;パフォーマンス向上の要&lt;/strong&gt;となるのが&lt;strong&gt;並列ファイル処理機能&lt;/strong&gt;です。無料版では1つずつファイルを順次処理するのに対し、寄付版では複数ファイルを同時に処理できるため、特にネットワーク共有やクラウドストレージでの同期が劇的に高速化されます。この機能だけで投資を回収できるレベルの改善を実感できます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;自動更新機能&lt;/strong&gt;により手動でのバージョン確認作業が不要になり、&lt;strong&gt;メール通知機能&lt;/strong&gt;では同期結果を自動で報告してくれます。さらに&lt;strong&gt;ポータブル版&lt;/strong&gt;として、USBメモリから直接実行できる形式も提供されます。&lt;/p&gt;&#10;&lt;h2 id="価格体系と寄付システムの仕組み"&gt;価格体系と寄付システムの仕組み&#10;&lt;/h2&gt;&lt;p&gt;寄付版は「&lt;strong&gt;You decide（あなたが決める）&lt;/strong&gt; 」という独自の価格設定を採用しています。寄付額は&lt;strong&gt;完全に任意&lt;/strong&gt;で、最低$1から自由に設定可能です。&lt;/p&gt;&#10;&lt;p&gt;これは固定価格のBusiness Edition（€20/デバイス/年）とは全く異なるシステムで、個人ユーザーが自分の価値観に基づいて金額を決められる柔軟な仕組みです。支払いはPayPal経由の一回払いで、サブスクリプションではありません。寄付後すぐにダウンロードリンクが提供され、Windows/Linux/macOS版すべてを同一寄付で利用できます。&lt;/p&gt;&#10;&lt;h2 id="無料版との詳細比較"&gt;無料版との詳細比較&#10;&lt;/h2&gt;&lt;h3 id="共通で利用できる充実機能"&gt;共通で利用できる充実機能&#10;&lt;/h3&gt;&lt;p&gt;無料版でも&lt;strong&gt;ファイル数や容量に制限がなく&lt;/strong&gt;、双方向同期・ミラー・更新の3つの同期モードを完備。FTP/FTPS/SFTP、Google Drive、MTPデバイス対応など、&lt;strong&gt;プロ仕様の機能がすべて無料&lt;/strong&gt;で利用できます。30以上の言語対応、バージョン管理、フィルタ機能、RealTimeSync付属なども含まれます。&lt;/p&gt;&#10;&lt;h3 id="寄付版限定の追加価値"&gt;寄付版限定の追加価値&#10;&lt;/h3&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;機能&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;無料版&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;寄付版&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ファイル処理方式&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;順次処理&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;並列処理&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;アップデート&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;手動確認&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;自動更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;同期結果通知&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;なし&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;メール送信&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;配布形態&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;インストール版のみ&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ポータブル版も提供&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;最も重要な違いは処理速度&lt;/strong&gt;です。大容量ファイルやネットワーク環境での同期において、並列処理により&lt;strong&gt;数倍から10倍以上の高速化&lt;/strong&gt;が報告されています。&lt;/p&gt;&#10;&lt;h2 id="競合他社との価格優位性"&gt;競合他社との価格優位性&#10;&lt;/h2&gt;&lt;p&gt;類似の有料ソフトウェアと比較すると、FreeFileSyncの価格優位性は明確です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;GoodSync&lt;/strong&gt;: $49.95/年（固定価格）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;SyncBackPro&lt;/strong&gt;: $55/年程度（固定価格）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ViceVersa&lt;/strong&gt;: $40～50/年（固定価格）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;FreeFileSync寄付版&lt;/strong&gt;: 任意の金額&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;自分で価格を決められる柔軟性&lt;/strong&gt;と、基本機能は完全無料という点で他社を大きく上回る価値提案となっています。&lt;/p&gt;&#10;&lt;h2 id="ユーザー評価とコミュニティの声"&gt;ユーザー評価とコミュニティの声&#10;&lt;/h2&gt;&lt;p&gt;Capterraでは&lt;strong&gt;4.4/5星&lt;/strong&gt;の高評価を獲得し、長期利用者から「高品質なソフトウェアに対する適正価格」との評価を得ています。IT専門家からは「€20/年は開発継続のために必要で妥当」という支持が多数あります。&lt;/p&gt;&#10;&lt;p&gt;一方で、Business Editionについては「年間€20は高い」「ライフタイムライセンスが欲しい」という価格への不満も一部で指摘されています。ただし、&lt;strong&gt;技術的品質については一貫して高評価&lt;/strong&gt;を維持しています。&lt;/p&gt;&#10;&lt;h2 id="使用許諾と制限事項"&gt;使用許諾と制限事項&#10;&lt;/h2&gt;&lt;p&gt;寄付版は&lt;strong&gt;個人利用限定&lt;/strong&gt;（寄付者と友人まで）で、商業利用には別途Business Edition（€20/デバイス/年）が必要です。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;FreeFileSyncの寄付版は、&lt;strong&gt;無料版で十分な機能を確認してから&lt;/strong&gt;検討できる低リスクな選択肢です。特にネットワーク環境での大容量同期や、メンテナンス作業の自動化を重視するユーザーには、自分が感じる価値に応じた金額を寄付することで、これらの機能を利用できます。&lt;/p&gt;&#10;&lt;p&gt;まずは無料版で機能を試用し、パフォーマンス向上や自動化機能に魅力を感じた場合に、自分にとって適切な金額での寄付を検討するのが最適なアプローチです。「You decide」という柔軟な価格設定により、ユーザーは自分の経済状況と得られる価値のバランスを考慮して支援額を決定でき、継続的な開発にも貢献できる理想的な選択肢として推奨できます。&lt;/p&gt;&#10;</description></item><item><title>[Mac] ForkLift 3と4の包括的比較</title><link>https://ai.hack-le.com/forklift-3%E3%81%A84%E3%81%AE%E5%8C%85%E6%8B%AC%E7%9A%84%E6%AF%94%E8%BC%83/</link><pubDate>Sun, 20 Jul 2025 16:56:27 +0900</pubDate><guid>https://ai.hack-le.com/forklift-3%E3%81%A84%E3%81%AE%E5%8C%85%E6%8B%AC%E7%9A%84%E6%AF%94%E8%BC%83/</guid><description>&lt;p&gt;ForkLift 4は大幅な機能向上を謳っているものの、&lt;strong&gt;既存ユーザーの多くが不満を抱く複雑なアップグレード&lt;/strong&gt;となっています。新しいライセンスモデルの導入、一部機能の削除、パフォーマンス改善の実感格差により、アップグレードの判断は慎重に行う必要があります。特に長期間ForkLift 3を愛用している場合、従来のワークフローが大きく変わる可能性があるため、具体的な利用シーンに応じた検討が重要です。&lt;/p&gt;&#10;&lt;h2 id="機能差分の詳細分析"&gt;機能差分の詳細分析&#10;&lt;/h2&gt;&lt;h3 id="forklift-4の主要新機能"&gt;ForkLift 4の主要新機能&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;クラウドサービス統合の強化&lt;/strong&gt;がForkLift 4の最大の売りです。Dropbox、Google Drive Team Drives、Microsoft OneDriveとの直接接続が可能になり、現代的なクラウドワークフローに対応しました。同期解析の&lt;strong&gt;最大20倍高速化&lt;/strong&gt;（公式発表）により、大容量ファイルの同期作業が劇的に改善されるとされています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;視覚的刷新&lt;/strong&gt;も大きな変更点です。8つの事前設定テーマに加えてカスタムテーマ作成機能、インターフェースカラーの完全カスタマイズが可能になりました。macOSの最新デザイン言語に合わせた現代的なUIにより、視覚的な統一感が向上しています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;生産性機能&lt;/strong&gt;では、Escキーで呼び出すQuick Openウィンドウ、iCloud経由での複数Mac間でのお気に入り同期、ワークスペース機能（レイアウトとタブ構成の保存）、タグ統合によるサイドバーでの素早いファイルフィルタリングなどが追加されました。&lt;/p&gt;&#10;&lt;h3 id="改善された既存機能"&gt;改善された既存機能&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ファイル操作&lt;/strong&gt;において、ローカルファイル操作の準備が最大10倍高速化され、ドラッグ&amp;amp;ドロップ機能が向上しました。&lt;strong&gt;プロトコルサポート&lt;/strong&gt;では、SFTP接続にOpenSSH実装を採用し、多要素認証（MFA）サポートを追加することで、接続の信頼性と互換性が向上しています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;多言語対応&lt;/strong&gt;も拡充され、日本語、中国語、チェコ語、スペイン語、イタリア語、ウクライナ語、ポーランド語が新たに追加されました。&lt;/p&gt;&#10;&lt;h3 id="削除廃止された機能"&gt;削除・廃止された機能&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;重要な機能削除&lt;/strong&gt;により、既存ユーザーからの強い反発を招いています。特に&lt;strong&gt;スペースバーによるファイル選択機能の削除&lt;/strong&gt;は、キーボード操作を重視するユーザーから大きな不満を集めています。Commander形式のキーボードショートカットスキーム、Touch Barサポートも廃止されました。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;UI情報密度の低下&lt;/strong&gt;により、従来のForkLift 3と比較して一画面に表示される情報量が減少し、効率性を重視するユーザーには不評です。&lt;/p&gt;&#10;&lt;h2 id="価格体系の根本的変更"&gt;価格体系の根本的変更&#10;&lt;/h2&gt;&lt;h3 id="forklift-4の新料金体系"&gt;ForkLift 4の新料金体系&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;個人ライセンス（1年間アップデート）&lt;/strong&gt; : $19.95 &lt;strong&gt;ファミリーライセンス（1年間アップデート）&lt;/strong&gt; : $29.95&lt;br&gt;&#10;&lt;strong&gt;スモールビジネス（1年間アップデート）&lt;/strong&gt; : $69.95&lt;/p&gt;&#10;&lt;p&gt;重要な変更点として、 &lt;strong&gt;「無期限ライセンス + 限定アップデート期間」モデル&lt;/strong&gt;を採用しています。アップデート期間終了後も現行バージョンは永続利用可能ですが、新しいアップデートを受けるには再度ライセンス購入が必要になります。&lt;/p&gt;&#10;&lt;h3 id="forklift-3からのアップグレード"&gt;ForkLift 3からのアップグレード&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;従来のアップグレード割引は廃止&lt;/strong&gt;され、既存ユーザーも正規価格での購入が必要です。ただし、既存ライセンスキー入力により&lt;strong&gt;100日間の追加アップデート期間&lt;/strong&gt;が付与されるボーナスがあります。&lt;/p&gt;&#10;&lt;p&gt;この価格モデル変更は&lt;strong&gt;コミュニティで大きな論争&lt;/strong&gt;を呼んでおり、長年のサポーターだった既存ユーザーから「見捨てられた」という声が多数上がっています。&lt;/p&gt;&#10;&lt;h2 id="パフォーマンス評価の現実"&gt;パフォーマンス評価の現実&#10;&lt;/h2&gt;&lt;h3 id="公式パフォーマンス主張-vs-実体験"&gt;公式パフォーマンス主張 vs 実体験&#10;&lt;/h3&gt;&lt;p&gt;BinaryNightsは&lt;strong&gt;同期解析の20倍高速化&lt;/strong&gt;を公式に主張していますが、&lt;strong&gt;実際のユーザー体験は大きく異なります&lt;/strong&gt;。複数のユーザーレポートによると、ForkLift 3では1秒未満だった同期解析がForkLift 4では40秒以上かかるケースが報告されており、パフォーマンス改善の実感は限定的です。&lt;/p&gt;&#10;&lt;h3 id="apple-siliconでの優位性"&gt;Apple Siliconでの優位性&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Apple Silicon（M1/M2/M3）環境&lt;/strong&gt;では、ForkLift 4が明確な優位性を示しています。CPU使用率が大幅に削減され、メモリ効率も向上しています。一方、Intel Macでは初期バージョンでCPUスパイクの問題があり、後のアップデートで解決されました。&lt;/p&gt;&#10;&lt;h3 id="実測可能な改善点"&gt;実測可能な改善点&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ローカルファイル操作の準備段階&lt;/strong&gt;では確実な高速化が確認されており、&lt;strong&gt;応答しないNASデバイスの処理&lt;/strong&gt;改善により、従来のハング現象が大幅に削減されています。&lt;/p&gt;&#10;&lt;h2 id="ユーザーコミュニティの厳しい評価"&gt;ユーザーコミュニティの厳しい評価&#10;&lt;/h2&gt;&lt;h3 id="アップグレード体験の二分化"&gt;アップグレード体験の二分化&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;満足した少数派ユーザー&lt;/strong&gt;: 主に基本的なデュアルペイン機能を使用し、クラウドストレージ統合を重視するユーザーが満足しています。Apple Siliconユーザーではパフォーマンス向上を実感する声もあります。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;不満を抱く多数派ユーザー&lt;/strong&gt;: 長期利用者からは「ForkLift 3に留まるべきだった」という後悔の声が多数上がっています。特に&lt;strong&gt;専門的なワークフローを持つユーザー&lt;/strong&gt;から、機能削除とライセンスモデル変更への強い反発があります。&lt;/p&gt;&#10;&lt;h3 id="具体的な不満点"&gt;具体的な不満点&#10;&lt;/h3&gt;&lt;p&gt;技術ブロガーのpawelgrzybek氏は「不満足なユーザーのグループに加わった。アナウンス投稿のコメント欄は、不公平なライセンスモデル、削除された機能、翻訳の欠落、悪いUI選択、安定性の問題を報告する印象に残らない顧客でいっぱいだ」と述べています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;キーボード効率の低下&lt;/strong&gt;、&lt;strong&gt;同期ワークフローの中断&lt;/strong&gt;、&lt;strong&gt;ファイル更新日時のバグ&lt;/strong&gt;などにより、実際の作業効率が低下したという報告が多数寄せられています。&lt;/p&gt;&#10;&lt;h2 id="macos対応状況と将来性"&gt;macOS対応状況と将来性&#10;&lt;/h2&gt;&lt;h3 id="対応os範囲"&gt;対応OS範囲&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ForkLift 3&lt;/strong&gt;: macOS 10.11（El Capitan）から最新のmacOS Sequoiaまで幅広くサポート &lt;strong&gt;ForkLift 4&lt;/strong&gt;: macOS 12.4（Monterey）以降が必須&lt;/p&gt;&#10;&lt;p&gt;この&lt;strong&gt;最小要件の大幅引き上げ&lt;/strong&gt;により、古いmacOSを使用するユーザーはForkLift 4へのアップグレードが物理的に不可能です。&lt;/p&gt;&#10;&lt;h3 id="将来のmacos互換性"&gt;将来のmacOS互換性&#10;&lt;/h3&gt;&lt;p&gt;ForkLift 4は&lt;strong&gt;SwiftUIベースの現代的アーキテクチャ&lt;/strong&gt;により、将来のmacOSバージョンとの互換性が期待できます。既にmacOS Sequoia完全対応、macOS Tahoe 26のベータサポートも提供されており、長期的な互換性において優位性があります。&lt;/p&gt;&#10;&lt;h2 id="アップグレード価値の総合判断"&gt;アップグレード価値の総合判断&#10;&lt;/h2&gt;&lt;h3 id="アップグレードを推奨する場合"&gt;アップグレードを推奨する場合&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;新規ユーザー&lt;/strong&gt;にとっては、ForkLift 4は合理的な選択肢です。最新のクラウドサービス統合、現代的なUI、将来のmacOS互換性を考慮すると、$19.95の価格は妥当といえます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;クラウド中心のワークフロー&lt;/strong&gt;を持つユーザー、&lt;strong&gt;Apple Siliconで基本機能を使用&lt;/strong&gt;するユーザー、&lt;strong&gt;将来のmacOS互換性を重視&lt;/strong&gt;するユーザーには明確なメリットがあります。&lt;/p&gt;&#10;&lt;h3 id="forklift-3継続を推奨する場合"&gt;ForkLift 3継続を推奨する場合&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;既存のワークフローが確立されているユーザー&lt;/strong&gt;、特に&lt;strong&gt;キーボードショートカット依存&lt;/strong&gt;、&lt;strong&gt;信頼性の高いファイル更新日時処理が必要&lt;/strong&gt;、&lt;strong&gt;従来のUIパラダイムを好む&lt;/strong&gt;ユーザーは、ForkLift 3の継続使用が現実的です。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;コストパフォーマンスを重視&lt;/strong&gt;するユーザーにとって、あるユーザーが計算したように「ForkLift 3を6年以上使用して年間コスト$1.40未満」という従来モデルの方が魅力的かもしれません。&lt;/p&gt;&#10;&lt;h3 id="代替案の検討"&gt;代替案の検討&#10;&lt;/h3&gt;&lt;p&gt;多くのレビューで&lt;strong&gt;Transmit 5&lt;/strong&gt;、&lt;strong&gt;Commander One PRO&lt;/strong&gt;、&lt;strong&gt;Path Finder&lt;/strong&gt;などの代替案も言及されており、ForkLift固有の機能に依存していない場合は、これらの選択肢も検討価値があります。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;ForkLift 4は&lt;strong&gt;技術的進歩と物議を醸すビジネス変更が共存する複雑なアップグレード&lt;/strong&gt;です。&lt;strong&gt;新規ユーザー&lt;/strong&gt;や&lt;strong&gt;現代的クラウドワークフローを求めるユーザー&lt;/strong&gt;には価値がありますが、&lt;strong&gt;既存の長期ユーザー&lt;/strong&gt;にとっては慎重な判断が必要です。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;最も重要な判断基準&lt;/strong&gt;は、現在のワークフローにおける具体的な改善ニーズと、新しいライセンスモデルへの受容度です。確実な価値を見出せない場合は、ForkLift 3の継続使用または代替アプリケーションの検討を推奨します。&lt;/p&gt;&#10;</description></item><item><title>[Linux] Pop!_OS 22.04で変換・無変換キーによる日本語入力切り替え設定（Mozc設定）</title><link>https://ai.hack-le.com/pop_os-22-04%E3%81%A7%E5%A4%89%E6%8F%9B%E3%83%BB%E7%84%A1%E5%A4%89%E6%8F%9B%E3%82%AD%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8B%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%85%A5%E5%8A%9B%E5%88%87%E3%82%8A%E6%9B%BF/</link><pubDate>Sun, 20 Jul 2025 09:43:18 +0900</pubDate><guid>https://ai.hack-le.com/pop_os-22-04%E3%81%A7%E5%A4%89%E6%8F%9B%E3%83%BB%E7%84%A1%E5%A4%89%E6%8F%9B%E3%82%AD%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8B%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%85%A5%E5%8A%9B%E5%88%87%E3%82%8A%E6%9B%BF/</guid><description>&lt;p&gt;Pop!_OS 22.04で、日本語キーボードの&lt;strong&gt;変換キー&lt;/strong&gt;と&lt;strong&gt;無変換キー&lt;/strong&gt;を使って日本語・英語入力を切り替える方法を説明します。&lt;strong&gt;Mozc設定のみ&lt;/strong&gt;で実現できる、シンプルで確実な方法です。&lt;/p&gt;&#10;&lt;h2 id="環境情報"&gt;環境情報&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: Pop!_OS 22.04&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;キーボード&lt;/strong&gt;: 日本語配列&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語入力システム&lt;/strong&gt;: ibus-mozc&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;h3 id="ibus-mozcのインストール確認"&gt;ibus-mozcのインストール確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# インストール確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dpkg -l | grep ibus-mozc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 未インストールの場合&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install ibus-mozc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="入力ソースの設定確認"&gt;入力ソースの設定確認&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;設定&lt;/strong&gt; → &lt;strong&gt;キーボード&lt;/strong&gt; → &lt;strong&gt;入力ソース&lt;/strong&gt;で以下が設定されていることを確認：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;英語（アメリカ合衆国）&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語（Mozc）&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-1-mozc設定画面を開く"&gt;Step 1: Mozc設定画面を開く&#10;&lt;/h2&gt;&lt;h3 id="方法1-トップバーから"&gt;方法1: トップバーから&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;画面右上の&lt;strong&gt;あ&lt;/strong&gt;または&lt;strong&gt;EN&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ツール&lt;/strong&gt; → &lt;strong&gt;プロパティ&lt;/strong&gt; を選択&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="方法2-アクティビティから"&gt;方法2: アクティビティから&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;アクティビティ&lt;/strong&gt;を開く&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Mozc&lt;/strong&gt;と検索して&lt;strong&gt;Mozc設定&lt;/strong&gt;を選択&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="step-2-キーマップの編集"&gt;Step 2: キーマップの編集&#10;&lt;/h2&gt;&lt;h3 id="キーマップ設定を開く"&gt;キーマップ設定を開く&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Mozc設定&lt;/strong&gt;ウィンドウで&lt;strong&gt;キー設定&lt;/strong&gt;タブを選択&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;キー設定の選択&lt;/strong&gt;の右側にある&lt;strong&gt;編集&lt;/strong&gt;ボタンをクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Mozcキーマップエディタ&lt;/strong&gt;が開く&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="新しいエントリの追加"&gt;新しいエントリの追加&#10;&lt;/h3&gt;&lt;h4 id="変換キーの設定日本語on"&gt;変換キーの設定（日本語ON）&#10;&lt;/h4&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;編集&lt;/strong&gt; → &lt;strong&gt;新しいエントリ&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;li&gt;以下のように設定：&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;モード&lt;/strong&gt;: 直接入力&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;キー&lt;/strong&gt;: &lt;code&gt;Henkan&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コマンド&lt;/strong&gt;: &lt;code&gt;IMEを有効化&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="無変換キーの設定日本語off"&gt;無変換キーの設定（日本語OFF）&#10;&lt;/h4&gt;&lt;ol&gt;&#10;&lt;li&gt;再び&lt;strong&gt;編集&lt;/strong&gt; → &lt;strong&gt;新しいエントリ&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;li&gt;以下のように設定：&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;モード&lt;/strong&gt;: 入力文字なし&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;キー&lt;/strong&gt;: &lt;code&gt;Muhenkan&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コマンド&lt;/strong&gt;: &lt;code&gt;IMEを無効化&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="設定の保存"&gt;設定の保存&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;OK&lt;/strong&gt;をクリックして設定を保存&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Mozc設定&lt;/strong&gt;ウィンドウも&lt;strong&gt;OK&lt;/strong&gt;で閉じる&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="step-3-動作確認"&gt;Step 3: 動作確認&#10;&lt;/h2&gt;&lt;h3 id="動作テスト"&gt;動作テスト&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;テキストエディタ&lt;/strong&gt;（geditなど）を開く&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;変換キー&lt;/strong&gt;を押す → 日本語入力モードになる&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;konnichiwa&lt;/code&gt; → スペースで変換 → &lt;code&gt;こんにちは&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;無変換キー&lt;/strong&gt;を押す → 英語入力モードになる&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;hello world&lt;/code&gt; → そのまま英語入力&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="トップバー表示の確認"&gt;トップバー表示の確認&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;変換キー後&lt;/strong&gt;: &lt;strong&gt;あ&lt;/strong&gt;（日本語モード）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;無変換キー後&lt;/strong&gt;: &lt;strong&gt;EN&lt;/strong&gt;または&lt;strong&gt;A&lt;/strong&gt;（英語モード）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="完成した環境"&gt;完成した環境&#10;&lt;/h2&gt;&lt;h3 id="使用方法"&gt;使用方法&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;変換キー&lt;/strong&gt;: 日本語入力モードに切り替え&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;無変換キー&lt;/strong&gt;: 英語入力モードに切り替え&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;スペースキー&lt;/strong&gt;: 日本語変換（日本語モード時）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="動作の特徴"&gt;動作の特徴&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;トグル動作ではない&lt;/strong&gt;: 各キーが専用機能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;状態を意識しなくて良い&lt;/strong&gt;: 迷わず確実に切り替え可能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Mac風の操作感&lt;/strong&gt;: 直感的な入力切り替え&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="トラブルシューティング"&gt;トラブルシューティング&#10;&lt;/h2&gt;&lt;h3 id="設定が効かない場合"&gt;設定が効かない場合&#10;&lt;/h3&gt;&lt;h4 id="ibus再起動"&gt;ibus再起動&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus-daemon -drx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="ログアウトログイン"&gt;ログアウト・ログイン&#10;&lt;/h4&gt;&lt;p&gt;一度ログアウトして再ログインすることで設定が反映される場合があります。&lt;/p&gt;&#10;&lt;h4 id="設定の確認"&gt;設定の確認&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Mozcキーマップエディタ&lt;/strong&gt;で設定したエントリが正しく保存されているか確認してください。&lt;/p&gt;&#10;&lt;h3 id="キーが認識されない場合"&gt;キーが認識されない場合&#10;&lt;/h3&gt;&lt;h4 id="キーコードの確認"&gt;キーコードの確認&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xev&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドで&lt;strong&gt;変換キー&lt;/strong&gt;と&lt;strong&gt;無変換キー&lt;/strong&gt;を押し、&lt;code&gt;Henkan&lt;/code&gt;、&lt;code&gt;Muhenkan&lt;/code&gt;として認識されているか確認してください。&lt;/p&gt;&#10;&lt;h4 id="他の設定との競合"&gt;他の設定との競合&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;gnome-tweaks&lt;/strong&gt;や&lt;strong&gt;カスタムキーバインド&lt;/strong&gt;で同じキーが使用されていないか確認してください。&lt;/p&gt;&#10;&lt;h3 id="一部のアプリで動作しない場合"&gt;一部のアプリで動作しない場合&#10;&lt;/h3&gt;&lt;h4 id="環境変数の確認"&gt;環境変数の確認&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo $GTK_IM_MODULE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo $QT_IM_MODULE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo $XMODIFIERS&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下のように設定されているか確認：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GTK_IM_MODULE=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;QT_IM_MODULE=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;XMODIFIERS=@im=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;未設定の場合は&lt;code&gt;~/.profile&lt;/code&gt;に追加：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export GTK_IM_MODULE=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export QT_IM_MODULE=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export XMODIFIERS=@im=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="設定のリセット"&gt;設定のリセット&#10;&lt;/h2&gt;&lt;h3 id="キーマップのリセット"&gt;キーマップのリセット&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Mozcキーマップエディタ&lt;/strong&gt;で：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;追加したエントリを選択&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;編集&lt;/strong&gt; → &lt;strong&gt;エントリを削除&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;または&lt;strong&gt;デフォルトに戻す&lt;/strong&gt;ボタンをクリック&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="完全なリセット"&gt;完全なリセット&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Mozc設定のリセット&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf ~/.config/mozc/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus-daemon -drx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Mozc設定のみ&lt;/strong&gt;で、変換・無変換キーによる日本語・英語入力切り替えが実現できます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;設定のポイント&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Mozc設定&lt;/strong&gt; → &lt;strong&gt;キー設定&lt;/strong&gt; → &lt;strong&gt;編集&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Henkan&lt;/strong&gt;キー → &lt;strong&gt;IMEを有効化&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Muhenkan&lt;/strong&gt;キー → &lt;strong&gt;IMEを無効化&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;&lt;strong&gt;利点&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;シンプル&lt;/strong&gt;: カスタムキーバインド不要&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;直感的&lt;/strong&gt;: Mac風の操作感&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;確実&lt;/strong&gt;: 状態を意識せずに切り替え可能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;標準的&lt;/strong&gt;: Mozc本来の機能を活用&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;この設定により、複雑なシステム設定を行うことなく、日本語キーボードの特性を活かした効率的な入力環境を構築できます。Pop!_OSでも他のLinuxディストリビューションと同様の快適な日本語入力が可能になります。&lt;/p&gt;&#10;</description></item><item><title>[Linux] Pop!_OS 22.04で日本語キーボードをUS配列として使う設定</title><link>https://ai.hack-le.com/linux-pop_os-22-04%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%92us%E9%85%8D%E5%88%97%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%86%E8%A8%AD%E5%AE%9A/</link><pubDate>Sun, 20 Jul 2025 08:24:09 +0900</pubDate><guid>https://ai.hack-le.com/linux-pop_os-22-04%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%92us%E9%85%8D%E5%88%97%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%86%E8%A8%AD%E5%AE%9A/</guid><description>&lt;p&gt;日本語配列の物理キーボードを、US配列のキーマップで使用する方法を説明します。Pop!_OSの独特な「入力ソース」の仕組みについても詳しく解説し、混乱しやすいポイントを明確にします。&lt;/p&gt;&#10;&lt;h2 id="環境情報"&gt;環境情報&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: Pop!_OS 22.04&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;物理キーボード&lt;/strong&gt;: 日本語配列&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;論理配列&lt;/strong&gt;: US配列（設定後）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="pop_osの入力ソースについて理解する"&gt;Pop!_OSの「入力ソース」について理解する&#10;&lt;/h2&gt;&lt;h3 id="一般的なlinuxとの違い"&gt;一般的なLinuxとの違い&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;通常のLinux&lt;/strong&gt;では：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;キーボードレイアウト&lt;/strong&gt;（物理的なキー配置）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;インプットメソッド&lt;/strong&gt;（日本語変換システム）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;が&lt;strong&gt;別々に管理&lt;/strong&gt;されます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Pop!_OSでは&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;両方とも &lt;strong&gt;「入力ソース」として同列に表示&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;これが混乱の原因&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="実際の入力ソース画面"&gt;実際の入力ソース画面&#10;&lt;/h3&gt;&lt;p&gt;設定 → キーボード → 入力ソースで、以下のように表示されます：&lt;/p&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2025/07/Screenshot-from-2025-07-20-08-10-44.png"&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;入力ソース:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────────────────┐&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 英語 (US) │ ← キーボードレイアウト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────────────────┤&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 日本語 (Mozc) │ ← インプットメソッド&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─────────────────┘&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;一見すると&lt;/strong&gt;同じ種類の設定に見えますが、&lt;strong&gt;実際には全く違う&lt;/strong&gt;ものです。&lt;/p&gt;&#10;&lt;h2 id="設定前後の比較"&gt;設定前後の比較&#10;&lt;/h2&gt;&lt;h3 id="日本語配列の場合"&gt;日本語配列の場合&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 2&lt;/strong&gt; → &lt;code&gt;&amp;quot;&lt;/code&gt;（ダブルクォート）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 6&lt;/strong&gt; → &lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 7&lt;/strong&gt; → &lt;code&gt;'&lt;/code&gt;（シングルクォート）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;@マーク&lt;/strong&gt; → 別の位置&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="us配列の場合設定後"&gt;US配列の場合（設定後）&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 2&lt;/strong&gt; → &lt;code&gt;@&lt;/code&gt;（アットマーク）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 6&lt;/strong&gt; → &lt;code&gt;^&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 7&lt;/strong&gt; → &lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&amp;ldquo;マーク&lt;/strong&gt; → Shift + &amp;rsquo; の位置&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-1-設定の変更"&gt;Step 1: 設定の変更&#10;&lt;/h2&gt;&lt;h3 id="設定アプリを開く"&gt;設定アプリを開く&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;アクティビティ&lt;/strong&gt;（画面左上）をクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;設定&lt;/strong&gt;を検索して開く&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="キーボード設定へ移動"&gt;キーボード設定へ移動&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;設定&lt;/strong&gt;内で&lt;strong&gt;キーボード&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;入力ソース&lt;/strong&gt;セクションを確認&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="us配列の追加"&gt;US配列の追加&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;入力ソース&lt;/strong&gt;の &lt;strong&gt;+&lt;/strong&gt; ボタンをクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;英語&lt;/strong&gt;を選択&lt;/li&gt;&#10;&lt;li&gt;英語（アメリカ合衆国）を選択&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;追加&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="重要日本語配列の削除"&gt;重要：日本語配列の削除&#10;&lt;/h3&gt;&lt;p&gt;もし&lt;strong&gt;日本語&lt;/strong&gt;（配列）が存在する場合：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語&lt;/strong&gt;を選択&lt;/li&gt;&#10;&lt;li&gt;−ボタンで削除&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: &lt;strong&gt;日本語 (Mozc)&lt;/strong&gt; は削除しないでください。これは日本語入力システムです。&lt;/p&gt;&#10;&lt;h2 id="step-2-入力ソースの理解と確認"&gt;Step 2: 入力ソースの理解と確認&#10;&lt;/h2&gt;&lt;h3 id="理想的な最終状態"&gt;理想的な最終状態&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;入力ソース:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────────────────┐&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 英語 (US) │ ← キーボードレイアウト（US配列）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────────────────┤&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 日本語 (Mozc) │ ← 日本語入力システム&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─────────────────┘&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="それぞれの役割"&gt;それぞれの役割&#10;&lt;/h3&gt;&lt;h4 id="英語-us"&gt;英語 (US)&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;種類&lt;/strong&gt;: キーボードレイアウト&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;役割&lt;/strong&gt;: 物理キーとシンボルの対応関係&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: Shift + 2 = @&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="日本語-mozc"&gt;日本語 (Mozc)&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;種類&lt;/strong&gt;: インプットメソッド&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;役割&lt;/strong&gt;: ローマ字→ひらがな変換&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: konnichiwa → こんにちは&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="コマンドでの確認"&gt;コマンドでの確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のキーボード設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setxkbmap -query&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 入力ソース設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings get org.gnome.desktop.input-sources sources&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;期待する出力：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# setxkbmap -query&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;layout: us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# gsettings（英語US + 日本語Mozc）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[(&amp;#39;xkb&amp;#39;, &amp;#39;us&amp;#39;), (&amp;#39;ibus&amp;#39;, &amp;#39;mozc-jp&amp;#39;)]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="物理的な動作確認"&gt;物理的な動作確認&#10;&lt;/h3&gt;&lt;p&gt;以下のキーを実際に押して確認：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 2&lt;/strong&gt; → &lt;code&gt;@&lt;/code&gt; が出力される&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 6&lt;/strong&gt; → &lt;code&gt;^&lt;/code&gt; が出力される&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shift + 7&lt;/strong&gt; → &lt;code&gt;&amp;amp;&lt;/code&gt; が出力される&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-3-よくある混乱と注意点"&gt;Step 3: よくある混乱と注意点&#10;&lt;/h2&gt;&lt;h3 id="混乱ポイント1-同じ入力ソースなのに違う種類"&gt;混乱ポイント1: 同じ「入力ソース」なのに違う種類&#10;&lt;/h3&gt;&lt;p&gt;Pop!_OSでは以下が同列に表示されます：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;英語 (US)&lt;/strong&gt; = キーボードレイアウト&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;英語 (UK)&lt;/strong&gt; = キーボードレイアウト&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ドイツ語&lt;/strong&gt; = キーボードレイアウト&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語&lt;/strong&gt; = キーボードレイアウト&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語 (Mozc)&lt;/strong&gt; = インプットメソッド&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;中国語 (Pinyin)&lt;/strong&gt; = インプットメソッド&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;実際には全く違う種類&lt;/strong&gt;の設定が混在しています。&lt;/p&gt;&#10;&lt;h3 id="混乱ポイント2-レイアウト変更の副作用"&gt;混乱ポイント2: レイアウト変更の副作用&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;キーボードレイアウトを変更すると&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;setxkbmap&lt;/code&gt;での設定（Ctrl/Capsスワップなど）がリセットされる&lt;/li&gt;&#10;&lt;li&gt;最後に選択したレイアウトが有効になる&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="注意点-削除する項目を間違えない"&gt;注意点: 削除する項目を間違えない&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;削除するもの&lt;/strong&gt;: &lt;strong&gt;日本語&lt;/strong&gt;（キーボードレイアウト）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;残すもの&lt;/strong&gt;: &lt;strong&gt;日本語 (Mozc)&lt;/strong&gt; （インプットメソッド）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-4-日本語入力との併用"&gt;Step 4: 日本語入力との併用&#10;&lt;/h2&gt;&lt;h3 id="使い分け"&gt;使い分け&#10;&lt;/h3&gt;&lt;p&gt;設定完了後の使い分け：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;英語 (US)&lt;/strong&gt; : 英語・記号入力（US配列）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語 (Mozc)&lt;/strong&gt; : 日本語入力（US配列ベース）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="切り替え方法"&gt;切り替え方法&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Super + Space&lt;/strong&gt;: 入力ソース切り替え&lt;/li&gt;&#10;&lt;li&gt;または&lt;strong&gt;無変換・変換キー&lt;/strong&gt;でのカスタム切り替え（別途設定が必要）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="トラブルシューティング"&gt;トラブルシューティング&#10;&lt;/h2&gt;&lt;h3 id="設定が反映されない場合"&gt;設定が反映されない場合&#10;&lt;/h3&gt;&lt;h4 id="ログアウトログイン"&gt;ログアウト・ログイン&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gnome-session-quit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="強制的なキーボード設定"&gt;強制的なキーボード設定&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setxkbmap us&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="複数のキーボードレイアウトがある場合"&gt;複数のキーボードレイアウトがある場合&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;問題&lt;/strong&gt;: 日本語配列とUS配列が両方存在 &lt;strong&gt;解決&lt;/strong&gt;: 不要な方（通常は日本語配列）を削除&lt;/p&gt;&#10;&lt;h3 id="ctrlcapsスワップがリセットされる場合"&gt;Ctrl/Capsスワップがリセットされる場合&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;: キーボードレイアウト変更による副作用 &lt;strong&gt;対策&lt;/strong&gt;: 自動起動スクリプトでの再適用&lt;/p&gt;&#10;&lt;h2 id="設定を元に戻す方法"&gt;設定を元に戻す方法&#10;&lt;/h2&gt;&lt;h3 id="日本語配列に戻す場合"&gt;日本語配列に戻す場合&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;設定&lt;/strong&gt; → &lt;strong&gt;キーボード&lt;/strong&gt; → &lt;strong&gt;入力ソース&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;+ボタンで日本語&lt;/strong&gt;を追加&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;英語（アメリカ合衆国）&lt;/strong&gt; を削除&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="コマンドでの変更"&gt;コマンドでの変更&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 日本語配列に戻す&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setxkbmap jp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;h3 id="pop_osの特徴"&gt;Pop!_OSの特徴&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;入力ソース&lt;/strong&gt;: キーボードレイアウトとインプットメソッドを統一表示&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;混乱しやすい&lt;/strong&gt;: 異なる種類の設定が同列に並ぶ&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;最後勝ち&lt;/strong&gt;: 最後に選択したキーボードレイアウトが有効&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="設定のポイント"&gt;設定のポイント&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;設定&lt;/strong&gt; → &lt;strong&gt;キーボード&lt;/strong&gt; → &lt;strong&gt;入力ソース&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;英語（アメリカ合衆国）&lt;/strong&gt; を追加&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語&lt;/strong&gt;（配列）を削除、&lt;strong&gt;日本語 (Mozc)&lt;/strong&gt; は保持&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="利点"&gt;利点&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;プログラミング&lt;/strong&gt;: 記号の位置がUS配列準拠&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;国際的な互換性&lt;/strong&gt;: 他の環境との一貫性&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語入力&lt;/strong&gt;: ibus-mozcとの併用可能&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="注意点"&gt;注意点&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;入力ソースの種類を理解&lt;/strong&gt;して設定&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;不要なレイアウトは削除&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;副作用（設定リセット）に注意&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;この設定により、物理的には日本語キーボードでありながら、論理的にはUS配列として快適に使用できます。Pop!_OSの独特な仕様を理解することで、混乱せずに設定・管理が可能になります。&lt;/p&gt;&#10;</description></item><item><title>[Linux] Pop!_OS 22.04でカスタムキーバインドを使った無変換・変換キーで入力ソースの切り替え</title><link>https://ai.hack-le.com/pop_os-22-04%E3%81%A7%E7%84%A1%E5%A4%89%E6%8F%9B%E3%83%BB%E5%A4%89%E6%8F%9B%E3%82%AD%E3%83%BC%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%83%BB%E8%8B%B1%E8%AA%9E%E5%85%A5/</link><pubDate>Sun, 20 Jul 2025 07:12:05 +0900</pubDate><guid>https://ai.hack-le.com/pop_os-22-04%E3%81%A7%E7%84%A1%E5%A4%89%E6%8F%9B%E3%83%BB%E5%A4%89%E6%8F%9B%E3%82%AD%E3%83%BC%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%83%BB%E8%8B%B1%E8%AA%9E%E5%85%A5/</guid><description>&lt;p&gt;（英かな変換するだけならmozcの設定で終わります）&lt;/p&gt;&#10;&lt;p&gt;Pop!_OS 22.04で、日本語キーボードの&lt;strong&gt;無変換キー&lt;/strong&gt;と&lt;strong&gt;変換キー&lt;/strong&gt;を使って日本語・英語入力を切り替える方法を説明します。この設定により、Windows環境と同様の快適な入力切り替えが可能になります。&lt;/p&gt;&#10;&lt;h2 id="環境情報"&gt;環境情報&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: Pop!_OS 22.04&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;キーボード&lt;/strong&gt;: 日本語配列&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語入力システム&lt;/strong&gt;: ibus-mozc&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="基本概念の理解"&gt;基本概念の理解&#10;&lt;/h2&gt;&lt;h3 id="入力システムの仕組み"&gt;入力システムの仕組み&#10;&lt;/h3&gt;&lt;p&gt;Linuxでの文字入力は、以下の2つのシステムが協調して動作します：&lt;/p&gt;&#10;&lt;h4 id="1-xkbキーボード配列"&gt;1. xkb（キーボード配列）&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;xkb&lt;/strong&gt; = X KeyBoard の略&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;役割&lt;/strong&gt;: 「どのキーを押したら、どの文字が出るか」を制御&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: Shift + 2 で @ が出るか &amp;quot; が出るかを決める&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="2-ibus日本語入力システム"&gt;2. ibus（日本語入力システム）&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ibus&lt;/strong&gt; = Intelligent Input Bus の略&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;役割&lt;/strong&gt;: ローマ字から日本語への変換&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: &lt;code&gt;konnichiwa&lt;/code&gt; → &lt;code&gt;こんにちは&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="入力ソースとは"&gt;入力ソースとは&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;入力ソース&lt;/strong&gt;は「入力方法」を表します：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;英語入力&lt;/strong&gt;: &lt;code&gt;('xkb', 'us')&lt;/code&gt; = US配列での直接入力&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日本語入力&lt;/strong&gt;: &lt;code&gt;('ibus', 'mozc-jp')&lt;/code&gt; = ibus-mozcを使った日本語変換&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-1-必要なソフトウェアの確認インストール"&gt;Step 1: 必要なソフトウェアの確認・インストール&#10;&lt;/h2&gt;&lt;h3 id="ibus-mozcのインストール"&gt;ibus-mozcのインストール&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# システム更新&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ibus-mozcのインストール&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install ibus-mozc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="環境変数について"&gt;環境変数について&#10;&lt;/h3&gt;&lt;p&gt;Pop!_OS 22.04では、ibus関連の環境変数は通常自動的に設定されています。明示的な設定は不要ですが、もし日本語入力が一部のアプリケーションで動作しない場合は、以下を&lt;code&gt;~/.profile&lt;/code&gt;に追加してください：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export GTK_IM_MODULE=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export QT_IM_MODULE=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;export XMODIFIERS=@im=ibus&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-入力ソースの設定確認"&gt;Step 2: 入力ソースの設定確認&#10;&lt;/h2&gt;&lt;h3 id="現在の設定確認"&gt;現在の設定確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings get org.gnome.desktop.input-sources sources&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;期待する出力：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[(&amp;#39;xkb&amp;#39;, &amp;#39;us&amp;#39;), (&amp;#39;ibus&amp;#39;, &amp;#39;mozc-jp&amp;#39;)]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定の意味：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;0番目&lt;/strong&gt;: &lt;code&gt;('xkb', 'us')&lt;/code&gt; = 英語（US配列）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;1番目&lt;/strong&gt;: &lt;code&gt;('ibus', 'mozc-jp')&lt;/code&gt; = 日本語入力&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="設定が不完全な場合"&gt;設定が不完全な場合&#10;&lt;/h3&gt;&lt;p&gt;もし上記と異なる出力の場合、&lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Region &amp;amp; Language&lt;/strong&gt; → &lt;strong&gt;Input Sources&lt;/strong&gt; で：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;English (US)&lt;/strong&gt; を追加&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Japanese (Mozc)&lt;/strong&gt; を追加&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="step-3-入力切り替えの動作確認"&gt;Step 3: 入力切り替えの動作確認&#10;&lt;/h2&gt;&lt;h3 id="ibusエンジンの理解"&gt;ibusエンジンの理解&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ibusエンジン&lt;/strong&gt;は「現在どの入力方法が有効か」を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のエンジン確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="手動切り替えテスト"&gt;手動切り替えテスト&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 英語入力に切り替え&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine xkb:us::eng&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のエンジン確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 日本語入力に切り替え&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine mozc-jp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のエンジン確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="入力テスト"&gt;入力テスト&#10;&lt;/h3&gt;&lt;p&gt;各エンジンで実際に入力テストを行います：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;英語エンジン&lt;/strong&gt;（&lt;code&gt;xkb:us::eng&lt;/code&gt;）の場合：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;hello world&lt;/code&gt; → そのまま &lt;code&gt;hello world&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;日本語エンジン&lt;/strong&gt;（&lt;code&gt;mozc-jp&lt;/code&gt;）の場合：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;konnichiwa&lt;/code&gt; → スペースキーで変換 → &lt;code&gt;こんにちは&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-4-切り替えスクリプトの作成"&gt;Step 4: 切り替えスクリプトの作成&#10;&lt;/h2&gt;&lt;h3 id="スクリプトファイルの作成"&gt;スクリプトファイルの作成&#10;&lt;/h3&gt;&lt;p&gt;手動でのコマンド実行は不便なので、スクリプトファイルを作成します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# スクリプト保存用ディレクトリ作成&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p ~/.local/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 英語切り替えスクリプト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; ~/.local/bin/switch-to-english.sh &amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine xkb:us::eng&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 日本語切り替えスクリプト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; ~/.local/bin/switch-to-japanese.sh &amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine mozc-jp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 実行権限の付与&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x ~/.local/bin/switch-to-*.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="スクリプトの動作確認"&gt;スクリプトの動作確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 英語切り替えテスト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/.local/bin/switch-to-english.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 日本語切り替えテスト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/.local/bin/switch-to-japanese.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-5-キーバインド設定"&gt;Step 5: キーバインド設定&#10;&lt;/h2&gt;&lt;h3 id="カスタムキーバインドとは"&gt;カスタムキーバインドとは&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;カスタムキーバインド&lt;/strong&gt;は「特定のキーを押したら、指定したコマンドを実行する」設定です。&lt;/p&gt;&#10;&lt;p&gt;例：無変換キーを押したら &lt;code&gt;switch-to-english.sh&lt;/code&gt; を実行&lt;/p&gt;&#10;&lt;h3 id="キーバインドの登録"&gt;キーバインドの登録&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# カスタムキーバインドの登録&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings &amp;#34;[&amp;#39;/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/muhenkan/&amp;#39;, &amp;#39;/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/henkan/&amp;#39;]&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="無変換キーの設定"&gt;無変換キーの設定&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 無変換キー = 英語切り替え&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/muhenkan/ name &amp;#39;English Input&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/muhenkan/ command &amp;#39;/home/$USER/.local/bin/switch-to-english.sh&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/muhenkan/ binding &amp;#39;Muhenkan&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="変換キーの設定"&gt;変換キーの設定&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 変換キー = 日本語切り替え&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/henkan/ name &amp;#39;Japanese Input&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/henkan/ command &amp;#39;/home/$USER/.local/bin/switch-to-japanese.sh&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/henkan/ binding &amp;#39;Henkan&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-6-動作確認と既知の問題"&gt;Step 6: 動作確認と既知の問題&#10;&lt;/h2&gt;&lt;h3 id="キーバインドテスト"&gt;キーバインドテスト&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;無変換キー&lt;/strong&gt;を押す → 英語入力に切り替わる&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;変換キー&lt;/strong&gt;を押す → 日本語入力に切り替わる&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="実際の入力テスト"&gt;実際の入力テスト&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;英語モード&lt;/strong&gt;（無変換キー後）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello world&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;日本語モード&lt;/strong&gt;（変換キー後）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;konnichiwa → こんにちは（スペースで変換）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pop_os特有の問題と対処法"&gt;Pop!_OS特有の問題と対処法&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;起動直後の日本語入力問題&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;現象&lt;/strong&gt;: 変換キーを押してもibus engineは切り替わるが、実際の日本語入力ができない&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;対処法&lt;/strong&gt;: 任意のアプリケーションで &lt;strong&gt;「カタカナひらがなローマ字」キー&lt;/strong&gt;を一度押す&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;その後&lt;/strong&gt;: 変換・無変換キーが正常に動作するようになる&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;この問題はPop!_OSのデスクトップ環境とibusの初期化タイミングに起因すると考えられます。一度初期化されれば、セッション中は安定して動作します。&lt;/p&gt;&#10;&lt;h2 id="完成した環境"&gt;完成した環境&#10;&lt;/h2&gt;&lt;h3 id="使用方法"&gt;使用方法&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;無変換キー&lt;/strong&gt;: 英語入力に切り替え&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;変換キー&lt;/strong&gt;: 日本語入力に切り替え&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;スペースキー&lt;/strong&gt;: 日本語変換（日本語モード時）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="設定の確認方法"&gt;設定の確認方法&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# キーバインド設定の確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings get org.gnome.settings-daemon.plugins.media-keys custom-keybindings&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のエンジン確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus engine&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 入力ソース確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings get org.gnome.desktop.input-sources sources&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="トラブルシューティング"&gt;トラブルシューティング&#10;&lt;/h2&gt;&lt;h3 id="キーバインドが効かない場合"&gt;キーバインドが効かない場合&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# スクリプトが実行できるか確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -la ~/.local/bin/switch-to-*.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# スクリプトを直接実行してテスト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/.local/bin/switch-to-english.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/.local/bin/switch-to-japanese.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pop_os特有の初期化問題"&gt;Pop!_OS特有の初期化問題&#10;&lt;/h3&gt;&lt;p&gt;起動直後は日本語入力が正常に動作しない場合があります。任意のアプリケーションで &lt;strong&gt;「カタカナひらがなローマ字」キー&lt;/strong&gt;を一度押すことで、ibusとアプリケーションの接続が初期化され、その後は変換・無変換キーが正常動作します。&lt;/p&gt;&#10;&lt;h3 id="ibus-daemonが起動していない"&gt;ibus-daemonが起動していない&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ibusデーモンの再起動&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus-daemon -drx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ibusの設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus-setup&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この設定により、日本語キーボードの無変換・変換キーを活用した効率的な入力切り替えが可能になります。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;設定の要点&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;入力ソース&lt;/strong&gt;: 英語（xkb:us）と日本語（ibus-mozc）を登録&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;スクリプト&lt;/strong&gt;: ibusエンジンを切り替えるコマンドをスクリプト化&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;キーバインド&lt;/strong&gt;: 無変換・変換キーにスクリプトを割り当て&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;Windows環境から移行したユーザーにとって、馴染みのある操作方法で快適な日本語入力環境を実現できます。&lt;/p&gt;&#10;</description></item><item><title>[Linux] Pop!_OS 22.04でCtrlとCaps Lockをスワップする方法（gnome-tweaks使用）</title><link>https://ai.hack-le.com/pop_os-22-04%E3%81%A7ctrl%E3%81%A8caps-lock%E3%82%92%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</link><pubDate>Sun, 20 Jul 2025 07:04:55 +0900</pubDate><guid>https://ai.hack-le.com/pop_os-22-04%E3%81%A7ctrl%E3%81%A8caps-lock%E3%82%92%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;Pop!_OS 22.04でCtrlとCaps Lockキーをスワップ（入れ替え）する方法を説明します。gnome-tweaksを使用した、標準的で確実な設定方法を紹介します。&lt;/p&gt;&#10;&lt;h2 id="環境情報"&gt;環境情報&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: Pop!_OS 22.04&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;デスクトップ環境&lt;/strong&gt;: GNOME（Cosmic拡張）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-1-gnome-tweaksのインストール"&gt;Step 1: gnome-tweaksのインストール&#10;&lt;/h2&gt;&lt;h3 id="インストール"&gt;インストール&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install gnome-tweaks&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="確認"&gt;確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gnome-tweaks&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;gnome-tweaksが起動することを確認してください。&lt;/p&gt;&#10;&lt;h2 id="step-2-ctrlcaps-lockスワップの設定"&gt;Step 2: Ctrl/Caps Lockスワップの設定&#10;&lt;/h2&gt;&lt;h3 id="gnome-tweaksでの設定"&gt;gnome-tweaksでの設定&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;gnome-tweaks&lt;/strong&gt;を起動&lt;/li&gt;&#10;&lt;li&gt;左側メニューから&lt;strong&gt;Keyboard &amp;amp; Mouse&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Additional Layout Options&lt;/strong&gt;をクリック&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Ctrl position&lt;/strong&gt;を展開&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Swap Ctrl and Caps Lock&lt;/strong&gt;にチェックを入れる&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="設定の確認"&gt;設定の確認&#10;&lt;/h3&gt;&lt;p&gt;設定後すぐに以下をテスト：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Caps Lockキー&lt;/strong&gt; + C → コピーできるか確認&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;元のCtrlキー&lt;/strong&gt;を押す → Caps Lockが有効になるか確認&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="step-3-設定の永続化確認"&gt;Step 3: 設定の永続化確認&#10;&lt;/h2&gt;&lt;h3 id="再起動テスト"&gt;再起動テスト&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;システムを再起動&lt;/li&gt;&#10;&lt;li&gt;起動後、Ctrl/Caps Lockスワップが維持されているか確認&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="コマンドでの確認"&gt;コマンドでの確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在のキーボード設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setxkbmap -query&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;options: ctrl:swapcaps&lt;/code&gt; が表示されていれば設定が有効です。&lt;/p&gt;&#10;&lt;h2 id="step-4-その他のキーボード設定"&gt;Step 4: その他のキーボード設定&#10;&lt;/h2&gt;&lt;h3 id="gnome-tweaksで設定可能な項目"&gt;gnome-tweaksで設定可能な項目&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Additional Layout Options&lt;/strong&gt;では他にも設定可能：&lt;/p&gt;&#10;&lt;h4 id="caps-lock設定"&gt;Caps Lock設定&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Caps Lock is disabled&lt;/strong&gt; - Caps Lock無効化&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Make Caps Lock an additional Ctrl&lt;/strong&gt; - Caps LockをCtrlに（スワップなし）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Swap Ctrl and Caps Lock&lt;/strong&gt; - 完全にスワップ&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="その他の便利な設定"&gt;その他の便利な設定&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Alt/Win key behavior&lt;/strong&gt; - AltとWinキーの動作&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Compose key&lt;/strong&gt; - 特殊文字入力キー&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Typing&lt;/strong&gt; - タイピング関連設定&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="トラブルシューティング"&gt;トラブルシューティング&#10;&lt;/h2&gt;&lt;h3 id="設定が反映されない場合"&gt;設定が反映されない場合&#10;&lt;/h3&gt;&lt;h4 id="ログアウトログイン"&gt;ログアウト・ログイン&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ターミナルでログアウト&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gnome-session-quit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="手動での確認"&gt;手動での確認&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 設定を手動で確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings get org.gnome.desktop.input-sources xkb-options&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="gnome-tweaksが起動しない場合"&gt;gnome-tweaksが起動しない場合&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 再インストール&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt remove gnome-tweaks&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install gnome-tweaks&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="設定が再起動後に消える場合"&gt;設定が再起動後に消える場合&#10;&lt;/h3&gt;&lt;p&gt;稀にPop!_OSの設定システムと競合する場合があります：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# dconfエディタで確認（上級者向け）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install dconf-editor&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dconf-editor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;org&lt;/strong&gt; → &lt;strong&gt;gnome&lt;/strong&gt; → &lt;strong&gt;desktop&lt;/strong&gt; → &lt;strong&gt;input-sources&lt;/strong&gt; → &lt;strong&gt;xkb-options&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h2 id="設定を元に戻す方法"&gt;設定を元に戻す方法&#10;&lt;/h2&gt;&lt;h3 id="gnome-tweaksでの無効化"&gt;gnome-tweaksでの無効化&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;gnome-tweaks&lt;/strong&gt; → &lt;strong&gt;Keyboard &amp;amp; Mouse&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Additional Layout Options&lt;/strong&gt; → &lt;strong&gt;Ctrl position&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Swap Ctrl and Caps Lock&lt;/strong&gt;のチェックを外す&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="コマンドでの無効化"&gt;コマンドでの無効化&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# すべてのキーボードオプションをクリア&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setxkbmap -option&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="その他の設定管理"&gt;その他の設定管理&#10;&lt;/h2&gt;&lt;h3 id="gnome-tweaksの利点"&gt;gnome-tweaksの利点&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;GUI操作&lt;/strong&gt;で分かりやすい&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;システムレベル&lt;/strong&gt;での設定&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;他の便利な設定&lt;/strong&gt;も同時に可能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Pop!_OSでも安定動作&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="設定の確認-1"&gt;設定の確認&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;gnome-tweaks&lt;/strong&gt;で設定した内容は以下で確認可能：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# GNOME設定の確認&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsettings get org.gnome.desktop.input-sources xkb-options&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 現在の有効な設定&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setxkbmap -query&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;gnome-tweaksを使用することで、スクリプトやコマンドを使わずに確実にCtrl/Caps Lockスワップを設定できます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;設定のポイント&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;gnome-tweaks&lt;/strong&gt;のインストール&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Keyboard &amp;amp; Mouse&lt;/strong&gt; → &lt;strong&gt;Additional Layout Options&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Ctrl position&lt;/strong&gt; → &lt;strong&gt;Swap Ctrl and Caps Lock&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;&lt;strong&gt;利点&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;GUI操作&lt;/strong&gt;で直感的&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;システムレベル&lt;/strong&gt;で永続化&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;追加設定&lt;/strong&gt;も同時に可能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;標準的な方法&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;この方法により、Pop!_OSでも他のLinuxディストリビューションと同様の標準的な手順でキーボード設定を管理できます。&lt;/p&gt;&#10;</description></item><item><title>[Linux] Pop!_OS + Windows デュアルブート時にブートメニューが表示されない問題の解決法</title><link>https://ai.hack-le.com/pop_os-windows-%E3%83%87%E3%83%A5%E3%82%A2%E3%83%AB%E3%83%96%E3%83%BC%E3%83%88%E6%99%82%E3%81%AB%E3%83%96%E3%83%BC%E3%83%88%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95/</link><pubDate>Sun, 20 Jul 2025 06:27:18 +0900</pubDate><guid>https://ai.hack-le.com/pop_os-windows-%E3%83%87%E3%83%A5%E3%82%A2%E3%83%AB%E3%83%96%E3%83%BC%E3%83%88%E6%99%82%E3%81%AB%E3%83%96%E3%83%BC%E3%83%88%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95/</guid><description>&lt;h2 id="問題の状況"&gt;問題の状況&#10;&lt;/h2&gt;&lt;h3 id="症状"&gt;症状&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;Pop!_OS 22.04をデュアルブートでインストール後、起動時にいきなりLinuxが立ち上がる&lt;/li&gt;&#10;&lt;li&gt;Windowsを起動するためには毎回BIOS画面に入ってF2連打が必要&lt;/li&gt;&#10;&lt;li&gt;ブートメニュー画面が表示されない&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="ハードウェア環境"&gt;ハードウェア環境&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;SSD1（Samsung 512GB）&lt;/strong&gt; : Windows 10/11システム領域（/dev/nvme0n1）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;SSD2（PNY 2TB）&lt;/strong&gt; : Pop!_OS 22.04システム領域 + Windowsデータ領域（/dev/nvme1n1）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;構成&lt;/strong&gt;: 各OSのシステム（ブート）領域が別々のSSDに分かれている&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ブートローダー&lt;/strong&gt;: systemd-boot（Pop!_OSのデフォルト）重要なポイント&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="原因の分析"&gt;原因の分析&#10;&lt;/h2&gt;&lt;h3 id="なぜブートメニューが表示されないのか"&gt;なぜブートメニューが表示されないのか&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Pop!_OSはsystemd-bootを使用&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;従来のGRUBとは異なる動作&lt;/li&gt;&#10;&lt;li&gt;デフォルトではタイムアウト設定なし&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;複数SSDによる複数EFIパーティション問題&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;SSD1のWindowsシステム&lt;/strong&gt;: &lt;code&gt;/dev/nvme0n1p1&lt;/code&gt; (EFIパーティション)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;SSD2のPop!_OSシステム&lt;/strong&gt;: &lt;code&gt;/dev/nvme1n1p1&lt;/code&gt; (EFIパーティション)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;問題の核心&lt;/strong&gt;: systemd-bootは同一EFIパーティション内のOSしか認識できない&lt;/li&gt;&#10;&lt;li&gt;物理的に異なるSSDにあるWindowsのEFIパーティションにはアクセス不可&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="確認コマンド"&gt;確認コマンド&#10;&lt;/h3&gt;&lt;p&gt;パーティション構成の確認：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fdisk -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ブートローダーの状態確認：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo bootctl status&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="試したが効果がなかった方法"&gt;試したが効果がなかった方法&#10;&lt;/h2&gt;&lt;h3 id="-systemd-bootのタイムアウト設定"&gt;❌ systemd-bootのタイムアウト設定&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# これらは機能しなかった&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo bootctl set-timeout 5 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nano /boot/efi/loader/loader.conf # 別EFIパーティションのWindowsは認識されず&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-手動でwindowsエントリ作成"&gt;❌ 手動でWindowsエントリ作成&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# windows.confを作成しても別EFIパーティションは参照できない&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nano /boot/efi/loader/entries/windows.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="-解決方法refindの導入"&gt;✅ 解決方法：rEFIndの導入&#10;&lt;/h2&gt;&lt;h3 id="refindとは"&gt;rEFIndとは&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;複数のEFIパーティションを横断してスキャンできるブートマネージャー&lt;/li&gt;&#10;&lt;li&gt;WindowsとLinuxの両方を自動検出&lt;/li&gt;&#10;&lt;li&gt;美しいGUIブートメニューを提供&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="インストール手順"&gt;インストール手順&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;rEFIndのインストール&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install refind&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;rEFIndのセットアップ&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo refind-install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="実行結果"&gt;実行結果&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;起動時に自動的にrEFIndメニューが表示される&lt;/li&gt;&#10;&lt;li&gt;WindowsとPop!_OSの両方がアイコン付きで表示される&lt;/li&gt;&#10;&lt;li&gt;矢印キーで選択、Enterで起動&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="なぜrefindで解決したのか"&gt;なぜrEFIndで解決したのか&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ブートローダー&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;対応範囲&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;複数EFI対応&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;systemd-boot&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;単一EFIパーティション内のみ&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;❌&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;rEFInd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;全EFIパーティションをスキャン&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✅&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;ポイント&lt;/strong&gt;: 各OSのシステム領域が別々のSSDにある場合、各SSDが独自のEFIパーティションを持つため、systemd-bootでは物理的に他のSSDのOSを認識できない&lt;/p&gt;&#10;&lt;h2 id="補足情報"&gt;補足情報&#10;&lt;/h2&gt;&lt;h3 id="一時的な回避方法"&gt;一時的な回避方法&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;起動時にBIOSブートメニューを表示&lt;/li&gt;&#10;&lt;li&gt;「Windows Boot Manager」を手動選択&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="注意点"&gt;注意点&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;rEFIndインストール後は、従来のsystemd-bootメニューは表示されなくなる&lt;/li&gt;&#10;&lt;li&gt;rEFIndが新しいメインブートローダーとなる&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;2枚のSSDに各OSのシステム領域が分かれているデュアルブート環境では、rEFIndを使うのが最適解&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;各SSDの独立したEFIパーティションを横断してスキャン&lt;/li&gt;&#10;&lt;li&gt;設定ファイルの手動編集不要&lt;/li&gt;&#10;&lt;li&gt;自動検出機能により確実に両方のOSを認識&lt;/li&gt;&#10;&lt;li&gt;インストールコマンド2つだけで完了&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;同一SSD内のパーティション分割デュアルブートとは異なる問題&lt;/strong&gt;であることを理解して、次回同じ状況になったら迷わずrEFIndを導入しましょう。&lt;/p&gt;&#10;</description></item><item><title>「変なおじさん（証明済み）」- メール認証技術の皮肉と現実</title><link>https://ai.hack-le.com/%E3%80%8C%E5%A4%89%E3%81%AA%E3%81%8A%E3%81%98%E3%81%95%E3%82%93%EF%BC%88%E8%A8%BC%E6%98%8E%E6%B8%88%E3%81%BF%EF%BC%89%E3%80%8D-%E3%83%A1%E3%83%BC%E3%83%AB%E8%AA%8D%E8%A8%BC%E6%8A%80%E8%A1%93%E3%81%AE/</link><pubDate>Wed, 16 Jul 2025 23:57:32 +0900</pubDate><guid>https://ai.hack-le.com/%E3%80%8C%E5%A4%89%E3%81%AA%E3%81%8A%E3%81%98%E3%81%95%E3%82%93%EF%BC%88%E8%A8%BC%E6%98%8E%E6%B8%88%E3%81%BF%EF%BC%89%E3%80%8D-%E3%83%A1%E3%83%BC%E3%83%AB%E8%AA%8D%E8%A8%BC%E6%8A%80%E8%A1%93%E3%81%AE/</guid><description>&lt;p&gt;以下を見てくれ、コイツをどう思う？&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;DKIM「そうです、私が変なおじさんです（証明済み）」&lt;/p&gt;&#10;&lt;p&gt;SPF「変じゃないオジさんリストをすべて洗い出せ。そして全員に通達せよ」&lt;/p&gt;&#10;&lt;p&gt;DMARC「変なおじさんは駆逐する！！心臓を捧げよ！！！」&lt;/p&gt;&#10;&lt;p&gt;DKIMはまぁ導入しやすいけどあんま意味ない&lt;/p&gt;&#10;&lt;p&gt;SPFは運用困難&lt;/p&gt;&#10;&lt;p&gt;DMARCは社内にエレン・イェーガーが必要&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;「DKIM『そうです、私が変なおじさんです（証明済み）』」—— DKIMは送信者の身元を暗号学的に証明する技術だが、結局のところ「このメールは確かに私が送りました」と証明するだけで、その「私」が信頼できるかどうかは全く別問題だ。spam.example.comから来たメールにDKIMが付いていて署名が有効でも、それは単に「このメールは確かにspam.example.comから送られました（証明済み）」という意味でしかない。&lt;/p&gt;&#10;&lt;p&gt;「SPF『変じゃないオジさんリストをすべて洗い出せ。そして全員に通達せよ』」—— これは現実の運用における悪夢を完璧に表現している。SPFは送信を許可するIPアドレスをすべて事前にリストアップする必要があるが、現代のメール環境では到底現実的ではない。Office 365、Google Workspace、各種SaaSサービス、外部委託先のシステム。新しいサービスを導入するたびにSPFレコードを更新し、各サービスのIP変更に追従し続けなければならない。まさに「変じゃないオジさんリスト」の管理は、組織の成長とともに破綻していく。&lt;/p&gt;&#10;&lt;p&gt;「DMARC『変なおじさんは駆逐する！！心臓を捧げよ！！！』」—— エレン・イェーガーの決め台詞を借りたこの表現が、DMARCの現実を見事に皮肉っている。DMARCポリシーを「reject」に設定するには、本当にエレン級の覚悟と組織全体を巻き込む強いリーダーシップが必要だ。しかし現実には、ほとんどの組織がp=noneで止まっている。&lt;/p&gt;&#10;&lt;h2 id="郵便ポストに求めるエントランスのセキュリティ"&gt;郵便ポストに求めるエントランスのセキュリティ&#10;&lt;/h2&gt;&lt;p&gt;メール認証技術の根本的な問題は、メールの本質を無視していることにある。メールはエントランスではなく郵便ポストだ。エントランスなら受付の人が来訪者と対話し、身分証明書を確認し、怪しければ断ることができる。しかし郵便ポストは一方的に投函され、開封するまで中身がわからず、差出人は簡単に偽装できる。&lt;/p&gt;&#10;&lt;p&gt;しかも問題の本質は「コストの低さ」にある。物理的な郵便なら用紙代、印刷代、郵送料がかかるが、メールは1億通送っても追加コストはほぼゼロだ。だから適当に詐欺メールを送りまくることができる。&lt;/p&gt;&#10;&lt;p&gt;そんな状況で「認めた住所からしか受け付けません」というのは、郵便ポストの利便性を完全に殺している。友人が新しいメールアドレスに変えた時に「SPFレコードに追加するまで待ってて」とか、初回取引の会社から「まずうちのドメインをホワイトリストに登録してください」とか、完全に本末転倒だ。メールの根本的な価値である「誰にでも届く」という特性を制限してしまったら、それはもうメールではない。&lt;/p&gt;&#10;&lt;h2 id="セキュリティという名の責任回避システム"&gt;セキュリティという名の責任回避システム&#10;&lt;/h2&gt;&lt;p&gt;皮肉なことに、実際のセキュリティ事故が起きた時の対応を見ると、みんなどれほど本気でセキュリティを重視しているかが露呈する。ベネッセの3500万件漏洩事故では、補償は500円の金券だった。KADOKAWAの「日本のインターネット史上最悪」とまで言われた漏洩事故も、特損20億円で済み、サービスは継続している。つまり、実際の被害はその程度なのだ。&lt;/p&gt;&#10;&lt;p&gt;しかし一方で、現場では「セキュリティインシデントが起きたら大変だ」「個人情報漏洩は企業にとって致命的」という前提で、無数の面倒な仕組みを導入させられている。実際には漏洩が起きても「すみませんでした、気をつけます」で終わりなのに、予防策だけは異常に複雑で高コスト。この温度差が、セキュリティ業界の「良いピラミッド」を支えている。&lt;/p&gt;&#10;&lt;p&gt;セキュリティという錦の御旗の下では、どんな要求でも正当化できてしまう。「何かあったら大変だから」という大義名分で、現実的でない運用を強制し、ユーザーの利便性を犠牲にし、「セキュリティ専門家」のポジションを確立できる。完璧な対策なんて存在しないから、いくらでも「まだ足りない」と言える。実際に被害が出れば「だから言ったでしょ」と言え、被害が出なければ「対策が効いた」と言える。&lt;/p&gt;&#10;&lt;h2 id="技術的権威による政治の隠蔽"&gt;技術的権威による政治の隠蔽&#10;&lt;/h2&gt;&lt;p&gt;DKIM/SPF/DMARCの話も、技術的には「メール認証の仕組み」だが、実質的にはIT部門と他部署の権力関係、セキュリティベンダーの営業戦略、「やってる感」を出すための政治的パフォーマンス、責任回避のための免罪符という政治的な話だ。セキュリティの本質は技術ではなく政治なのに、「技術的に正しい」という権威を使って政治的議論を封じ込めている。&lt;/p&gt;&#10;&lt;p&gt;結局、企業の「セキュリティ事故が起きても俺のせいじゃない」「ちゃんと対策してたって言えるようにしたい」「でも実際には面倒なことはしたくない」というニーズを、エンジニアが技術という権威で拾っただけなのではないか。実際には運用は現実的じゃなく、効果も限定的だが、「業界標準の対策をしてます」と言える完璧な責任回避システムが完成する。&lt;/p&gt;&#10;&lt;p&gt;事故が起きても「DMARC設定してました、でも技術的限界があって&amp;hellip;」と言えるし、何も起きなければ「我々の対策が効果的でした」と言える。技術的に正しいという権威を使って、政治的に都合の良い仕組みを正当化する構造がここにある。&lt;/p&gt;&#10;&lt;h2 id="結局は全通しという現実"&gt;結局は全通しという現実&#10;&lt;/h2&gt;&lt;p&gt;実際のところ、多くの組織は結局「全通し」に近い状態になっている。SPFやDKIMの設定ミスで正当なメールが弾かれるリスク、「お客様からの重要なメールが届かない」クレームの怖さ、新しいサービスや取引先からのメール送信への対応コストを考えると、「迷惑メール対策はやってる感じにしつつ、でも基本的には通す」という運用になりがちだ。&lt;/p&gt;&#10;&lt;p&gt;DMARCもp=noneで放置、p=quarantineにしても隔離されたメールは結局手動で確認して通す、p=rejectは怖すぎて設定できないという状況で、「技術的には対策してるけど、実質的には昔とあまり変わらない」状態の組織が多い。&lt;/p&gt;&#10;&lt;p&gt;皮肉なことに、これらのセキュリティ対策を真面目にやるのは、スパマーや詐欺業者、金に目がくらんだサイト運営者だったりする。彼らは信頼性演出のため、騙すため、捕まらないために、SSL証明書を当然のように取得し、HTTPS対応を完璧にし、セキュリティ対策もプロ仕様だ。結果として「安全なサイト」扱いを受ける。&lt;/p&gt;&#10;&lt;p&gt;一方、善良な個人の手作りサイトは「危険です！」と警告される。セキュリティ対策が、悪い人ほどちゃんとやる仕組みになっていて、善良な個人ほど排除される構造ができあがっている。&lt;/p&gt;&#10;&lt;h2 id="変なおじさんの正体"&gt;変なおじさんの正体&#10;&lt;/h2&gt;&lt;p&gt;結局のところ、メール認証技術が皮肉られるのは、理想と現実のギャップがあまりにも大きすぎるからだ。技術的には「正しい」ことをやっているつもりでも、実際の運用は破綻し、本来の目的は達成されず、新たな複雑さだけが追加される。&lt;/p&gt;&#10;&lt;p&gt;「変なおじさん（証明済み）」という表現は、身元ははっきりしているけれど、だからといって信頼できるわけではないという微妙なポジションを完璧に言い表している。セキュリティ技術の多くが、実はこの「変なおじさん」なのかもしれない。やってる感は十分だが、実際の効果は疑問で、むしろ面倒さだけが増えている。&lt;/p&gt;&#10;&lt;p&gt;技術者が「技術で解決」に逃げることで、組織の根本的な問題から目を逸らし続ける構造。その結果として、誰も幸せにしない高性能なシステムが完成する。これこそが、現代の技術的解決主義の病理なのではないだろうか。&lt;/p&gt;&#10;</description></item><item><title>WordPress 6.8.2完全ガイド</title><link>https://ai.hack-le.com/wordpress-6-8-2%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89/</link><pubDate>Wed, 16 Jul 2025 03:51:21 +0900</pubDate><guid>https://ai.hack-le.com/wordpress-6-8-2%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89/</guid><description>&lt;p&gt;WordPress 6.8.2は2025年7月15日にリリースされた重要なメンテナンスリリースです。この更新は新機能の追加ではなく、&lt;strong&gt;20のコア修正と15のブロックエディター改善&lt;/strong&gt;に焦点を当てた安定性向上のリリースとなっています。&lt;/p&gt;&#10;&lt;h2 id="リリース概要と重要な変更点"&gt;リリース概要と重要な変更点&#10;&lt;/h2&gt;&lt;p&gt;WordPress 6.8.2は&lt;strong&gt;ショートサイクルメンテナンスリリース&lt;/strong&gt;として位置づけられ、WordPress 6.8で導入された機能の不具合修正と性能向上を目的としています。リリースは@audrasjb、@estelaris、@zunaid321によって主導されました。&lt;/p&gt;&#10;&lt;p&gt;このバージョンで最も重要な変更は、&lt;strong&gt;WordPress 4.1-4.6のセキュリティサポート終了&lt;/strong&gt;と、&lt;strong&gt;bcryptパスワードハッシュ化&lt;/strong&gt;の継続的な改善です。日本のWordPress開発者コミュニティでは、特にbcryptへの移行による下位互換性の問題について活発な議論が行われています。&lt;/p&gt;&#10;&lt;h2 id="主な修正内容と改善点"&gt;主な修正内容と改善点&#10;&lt;/h2&gt;&lt;h3 id="コア修正20項目"&gt;コア修正（20項目）&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;テーマ関連の重要な修正&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Twenty Twenty-Five&lt;/strong&gt;：エディタースタイルが読み込まれない問題を修正&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Twenty Sixteen&lt;/strong&gt;：引用ブロックのプレーンスタイルでエディターに枠線が表示される問題を解決&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Twenty Fourteen&lt;/strong&gt;：最新コメントブロックのリンク色がコンテンツサイドバーに適用される問題を修正&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Twenty Twenty-One&lt;/strong&gt;：メニュートグルが「load」イベント後まで反応しない問題を解決&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;メディア処理の改善&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Mac スクリーンショットアップロード問題&lt;/strong&gt;：ファイル名にクエスチョンマークが挿入され画像が破損する問題を修正&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;oEmbed プロバイダー変更&lt;/strong&gt;：app.screencast.com の削除と HTTP から HTTPS への移行&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;開発環境の強化&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ブロックエディタースタイルの開発モード&lt;/strong&gt;導入&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Twemoji v16.0.1&lt;/strong&gt;への更新&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;TinyMCE キャッシュキー&lt;/strong&gt;の更新によるパフォーマンス向上&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="ブロックエディター改善15項目"&gt;ブロックエディター改善（15項目）&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ナビゲーションブロック&lt;/strong&gt;：パフォーマンス最適化と有効性チェック改善&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;クエリループ&lt;/strong&gt;：&amp;lsquo;query.inherit&amp;rsquo; 属性値の上書き防止&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;画像ブロック&lt;/strong&gt;：ライブラリから同じ画像を再選択時の古いURL問題を修正&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;詳細ブロック&lt;/strong&gt;：すべての非インタラクティブフォーマットを有効化し、キーボードアクセシビリティを改善&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;メディアプレースホルダー&lt;/strong&gt;：ローカルURLパスを許可するメディアURL入力タイプの回帰を修正&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="システム要件"&gt;システム要件&#10;&lt;/h2&gt;&lt;p&gt;WordPress 6.8.2は&lt;strong&gt;WordPress 6.8と同じシステム要件&lt;/strong&gt;を維持しています：&lt;/p&gt;&#10;&lt;h3 id="最小要件"&gt;最小要件&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;PHP&lt;/strong&gt;: バージョン7.4以上&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;: バージョン5.7以上 または &lt;strong&gt;MariaDB&lt;/strong&gt;: バージョン10.4以上&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;HTTPS&lt;/strong&gt;: サポート必須&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ウェブサーバー&lt;/strong&gt;: Apache または Nginx（推奨）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="推奨要件"&gt;推奨要件&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;PHP&lt;/strong&gt;: バージョン8.0以上（最適なパフォーマンスのため）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;: バージョン8.0以上 または &lt;strong&gt;MariaDB&lt;/strong&gt;: バージョン10.6以上&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: 最小512MB（大規模サイトには8GB推奨）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;日本のホスティングプロバイダーであるKUSANAGIチームは、PHP 8.xとの互換性について詳細な技術分析を提供しており、パフォーマンス向上のためのPHP 8.0以上の使用を強く推奨しています。&lt;/p&gt;&#10;&lt;h2 id="インストールとアップデート方法"&gt;インストールとアップデート方法&#10;&lt;/h2&gt;&lt;h3 id="自動更新推奨"&gt;自動更新（推奨）&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;WordPressダッシュボードにログイン&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;ダッシュボード」＞「更新&lt;/strong&gt;」に移動&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;今すぐ更新&lt;/strong&gt;」ボタンをクリック&lt;/li&gt;&#10;&lt;li&gt;WordPressが自動的に6.8.2をダウンロード・インストール&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="手動更新"&gt;手動更新&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://wordpress.org/download/release-archive/" target="_blank" rel="noopener"&#10; &gt;https://wordpress.org/download/release-archive/&lt;/a&gt; からWordPress 6.8.2をダウンロード&lt;/li&gt;&#10;&lt;li&gt;FTPまたはホスティングコントロールパネルでファイルをアップロード&lt;/li&gt;&#10;&lt;li&gt;標準的なWordPressアップグレード手順に従う&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="wp-cli使用"&gt;WP-CLI使用&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wp core update https://wordpress.org/wordpress-6.8.2.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="既知の問題と注意点"&gt;既知の問題と注意点&#10;&lt;/h2&gt;&lt;h3 id="重要な互換性問題"&gt;重要な互換性問題&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;マルチサイト環境での問題&lt;/strong&gt;：一部のユーザーでマルチサイトインストールでドメインマッピングに関する問題が報告されています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;パスワードハッシュ化の変更&lt;/strong&gt;：日本の開発者コミュニティ（特にSWELLテーマ開発者）は、WordPress 6.8でのbcryptパスワードハッシュ化について警告しています。「6.8にアップデート後にダウングレードすると、bcrypt/MD5の非互換性によりパスワード認証が失敗する可能性がある」とされています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;SEOプラグインとの競合&lt;/strong&gt;：Yoast SEOなど一部のSEOプラグインで投稿エディターのレイアウト問題が報告されています。&lt;/p&gt;&#10;&lt;h3 id="パフォーマンスへの影響"&gt;パフォーマンスへの影響&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;メモリリーク修正&lt;/strong&gt;：do_blocks()関数でのメモリリークが修正され、サイトパフォーマンスが向上しました。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;キャッシュ改善&lt;/strong&gt;：TinyMCEキャッシュキーの更新により、エディターの読み込み速度が改善されています。&lt;/p&gt;&#10;&lt;h2 id="日本語コミュニティからの反応"&gt;日本語コミュニティからの反応&#10;&lt;/h2&gt;&lt;h3 id="翻訳と地域化の状況"&gt;翻訳と地域化の状況&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;翻訳チームの活動&lt;/strong&gt;：日本のWordPress翻訳チームは積極的に活動しており、すべてのWordPress 6.8.2ドキュメントが日本語に翻訳されています。WordPress 6.5で導入された改良された翻訳システム（gettextからPHPベースの翻訳ファイルへの移行）により、パフォーマンスが向上しています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;コミュニティエンゲージメント&lt;/strong&gt;：WordCamp Japan コミュニティはWordPress 6.8の変更について活発に議論しており、日本全国の25のWordPress Meetupグループがボランティアメンバーによって管理されています。&lt;/p&gt;&#10;&lt;h3 id="開発者とテーマ制作者の対応"&gt;開発者とテーマ制作者の対応&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;主要な日本のプラグイン開発者&lt;/strong&gt;：不動産プラグインシリーズなどの主要な日本のプラグイン開発者がWordPress 6.8対応版をリリースしています。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;テーマ開発者の分析&lt;/strong&gt;：Vektor Inc.（Lightningテーマ開発者）やTCDテーマ開発者は、WordPress 6.8の変更点と日本のユーザーへの影響について包括的なガイドを提供しています。&lt;/p&gt;&#10;&lt;h2 id="前バージョンからの変更点"&gt;前バージョンからの変更点&#10;&lt;/h2&gt;&lt;h3 id="wordpress-681からの変更"&gt;WordPress 6.8.1からの変更&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;追加の20のコア修正&lt;/strong&gt;（6.8.1では15の修正）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;15のブロックエディター改善&lt;/strong&gt;（6.8.1と同様の範囲）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;同梱テーマ固有の修正&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;メディア処理の改善&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;開発環境の強化&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="wordpress-680からの主な違い"&gt;WordPress 6.8.0からの主な違い&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;新機能なし&lt;/strong&gt; - 純粋にメンテナンス重視&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;既存のWordPress 6.8機能の安定性向上&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;6.8.0リリース後に発見された問題の修正&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ブロックエディターとコア機能のパフォーマンス最適化&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="今後の展望と推奨事項"&gt;今後の展望と推奨事項&#10;&lt;/h2&gt;&lt;h3 id="ウェブサイト所有者への推奨"&gt;ウェブサイト所有者への推奨&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;即座にアップデート&lt;/strong&gt;してバグ修正と改善の恩恵を受ける&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;カスタムテーマやプラグインで徹底的にテスト&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;アップデート前にサイトをバックアップ&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;プラグインのWordPress 6.8.2互換性を確認&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="開発者への推奨"&gt;開発者への推奨&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;ブロックエディターAPIの技術的変更を確認&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;カスタムブロックとテーマの互換性をテスト&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;影響を受けるWordPress関数を使用している場合はプラグインコードを更新&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;将来の開発で非推奨機能を考慮&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;WordPress 6.8.2は、35の総修正（20のコア + 15のブロックエディター）により、WordPress 6.8の全体的な安定性を向上させる堅実なメンテナンスリリースです。新機能は導入されていませんが、ユーザーエクスペリエンスに影響を与える重要な問題を修正しており、すべてのWordPress 6.8ユーザーにとって価値のあるアップデートとなっています。&lt;/p&gt;&#10;&lt;p&gt;WordPress 4.1-4.6のセキュリティアップデート終了は、WordPressの進化における重要な節目を示しており、セキュリティとパフォーマンスの利点のためにより新しいバージョンを維持することの重要性を強調しています。&lt;/p&gt;&#10;&lt;p&gt;日本のWordPressコミュニティは引き続き活発で、翻訳・地域化の取り組みが強力に続いており、グローバルなWordPressエコシステムの変化にもかかわらず、技術的な分析とユーザーガイダンスを提供し続けています。&lt;/p&gt;&#10;</description></item><item><title>【完全解説】LinuxのVNCサーバーを自動起動する設定</title><link>https://ai.hack-le.com/%E3%80%90%E5%AE%8C%E5%85%A8%E8%A7%A3%E8%AA%AC%E3%80%91linux%E3%81%AEvnc%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%82%92%E8%87%AA%E5%8B%95%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E8%A8%AD%E5%AE%9A/</link><pubDate>Mon, 23 Jun 2025 02:46:39 +0900</pubDate><guid>https://ai.hack-le.com/%E3%80%90%E5%AE%8C%E5%85%A8%E8%A7%A3%E8%AA%AC%E3%80%91linux%E3%81%AEvnc%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%82%92%E8%87%AA%E5%8B%95%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E8%A8%AD%E5%AE%9A/</guid><description>&lt;p&gt;前提記事&lt;/p&gt;&#10;&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/mac-pop_os-tigervnc/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;MacからPop!_OSをリモート操作！TigerVNCサーバー設定完全ガイド&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/mac-pop_os-tigervnc/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2025/12/output-110.webp" alt="MacからPop!_OSをリモート操作！TigerVNCサーバー設定完全ガイド" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;Linuxをリモート操作したいけど、設定が複雑で諦めかけていませんか？この記事では、最もシンプルかつ確実にVNC（Virtual Network Computing）接続を実現する方法を解説します。&lt;/p&gt;&#10;&lt;p&gt;複雑な&lt;code&gt;systemd&lt;/code&gt;の設定に悩む必要はありません。各行が何のためにあるのかを一つずつ理解すれば、誰でもVNCサーバーの自動起動をマスターできます。&lt;strong&gt;この記事は設定ファイルのコピペではなく、理解を目的としています&lt;/strong&gt;。理解すれば、自身の環境に合わせてカスタマイズできるでしょう。&lt;/p&gt;&#10;&lt;h2 id="なぜsystemdを使うのか"&gt;なぜ&lt;code&gt;systemd&lt;/code&gt;を使うのか？&#10;&lt;/h2&gt;&lt;p&gt;VNCサーバーの自動起動には、ユーザーがログインした後にVNCサーバーを起動する方法と、OS起動と同時に自動で起動する&lt;code&gt;systemd&lt;/code&gt;を使う方法があります。&lt;code&gt;systemd&lt;/code&gt;を使うメリットは以下の通りです。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;OS起動と同時起動&lt;/strong&gt;: ユーザーがログインしていなくても、PCを起動すれば自動的にVNCサーバーが動きます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;安定したプロセス管理&lt;/strong&gt;: サービスが予期せず終了した場合でも、&lt;code&gt;systemd&lt;/code&gt;が監視し、設定によっては自動的に再起動を試みることができます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="サービスファイルの内容"&gt;サービスファイルの内容&#10;&lt;/h2&gt;&lt;p&gt;今回解説する&lt;code&gt;systemd&lt;/code&gt;サービスファイルは以下の通りです。このファイルを&lt;code&gt;/etc/systemd/system/vncserver_yourusername.service&lt;/code&gt;(例: &lt;code&gt;/etc/systemd/system/vncserver_user.service&lt;/code&gt; のように、&lt;code&gt;yourusername&lt;/code&gt;の部分をVNCセッションで使いたいユーザー名に置き換えてください) のように保存します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Remote desktop service &lt;span class="o"&gt;(&lt;/span&gt;VNC&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;network.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;forking&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yourusername&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yourusername&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/yourusername&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStartPre&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/sh -c &lt;span class="s1"&gt;&amp;#39;/usr/bin/vncserver -kill :2 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 || :&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/vncserver -localhost no :2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/vncserver -kill :2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Install&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="各行の完全解説"&gt;各行の完全解説&#10;&lt;/h2&gt;&lt;p&gt;ここから、サービスファイルの各行が何を示しているのか、その意味や目的を具体的に見ていきましょう。それぞれの項目が「必須」なのか「任意」なのかも明確に示します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="unit-セクション"&gt;&lt;code&gt;[Unit]&lt;/code&gt; セクション&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、systemdサービスファイルを構成するセクションの「見出し」です。この行は必須です。このセクションには、サービスに関する一般的な情報や、他のサービスとの関係が記述されます。systemdに決められたキーワードであり、[Hoge]のような任意の文字列にはできません。ファイルの中で必ずしも一行目である必要はありません。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Remote desktop service &lt;span class="o"&gt;(&lt;/span&gt;VNC&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、このサービスが何をするものなのかを説明するテキストです。systemctl status vncserver_yourusername.serviceコマンドなどでサービスの状況を見たときに表示される、人間が読んでわかる説明文です。これは任意ですが、記述することが強く推奨されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;network.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、このサービスが起動するタイミングを指定しています。この行は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: このサービスは、&lt;code&gt;network.target&lt;/code&gt;という別のサービスが起動を完了した「後で」起動すべきであることを&lt;code&gt;systemd&lt;/code&gt;に指示しています。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;具体例&lt;/strong&gt;: VNCサーバーはネットワークがないと機能しません。&lt;code&gt;network.target&lt;/code&gt;は、&lt;code&gt;systemd&lt;/code&gt;によって定義された &lt;strong&gt;「コンピューターのネットワークが使える状態」を示す標準の目印（ターゲット）&lt;/strong&gt; です。この設定により、VNCサーバーはネットワークが利用可能になってから起動します。&lt;code&gt;network.target&lt;/code&gt;は、&lt;code&gt;/usr/lib/systemd/system/network.target&lt;/code&gt;のようなパスにファイルとして存在し、&lt;code&gt;systemd&lt;/code&gt;の開発者によって定義された共通の「決められた名前」です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="service-セクション"&gt;&lt;code&gt;[Service]&lt;/code&gt; セクション&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、systemdサービスファイルの別のセクションの開始を示す見出しです。このセクションには、実際にサービスがどのように実行されるかに関する、具体的な設定が記述されます。この行は必須です。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;forking&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、サービスが起動する際の「動作の種類」をsystemdに伝える設定です。この項目は必須です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: &lt;code&gt;forking&lt;/code&gt;は、&lt;code&gt;ExecStart&lt;/code&gt;で指定されたコマンドが起動時に&lt;strong&gt;自分自身をバックグラウンドに「放り出し」（フォークし）、元の起動元のプロセスは終了する&lt;/strong&gt;タイプを示します。&lt;code&gt;systemd&lt;/code&gt;はこのフォークされたバックグラウンドプロセスのPID（プロセスID）を特定し、サービスが起動したと判断します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;理由&lt;/strong&gt;: &lt;code&gt;/usr/bin/vncserver&lt;/code&gt;スクリプトは、内部でVNCサーバー本体のプロセスを起動し、そのプロセスをバックグラウンドに送ってから自分自身は終了するという挙動をするため、このタイプが適合します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yourusername&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、このサービスがどのユーザーの権限で実行されるかを指定します。この行は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: ここに指定したユーザー名（例: &lt;code&gt;taku&lt;/code&gt;）のユーザーID（UID）と、そのユーザーのプライマリグループIDに切り替えてサービスを実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;具体例&lt;/strong&gt;: &lt;code&gt;User=yourusername&lt;/code&gt;と指定した場合、VNCサーバーは&lt;code&gt;yourusername&lt;/code&gt;ユーザーとして動作します。これにより、&lt;code&gt;/home/yourusername/.vnc/passwd&lt;/code&gt;のようなユーザーのホームディレクトリ内のファイルにアクセスできるようになります。この行を省略すると、サービスは通常&lt;code&gt;root&lt;/code&gt;ユーザーの権限で実行されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;注意点&lt;/strong&gt;: ここには&lt;strong&gt;必ずシステムに存在するユーザー名&lt;/strong&gt;を指定してください。存在しないユーザー名を指定すると、サービスは起動に失敗します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yourusername&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、このサービスがどのグループの権限で実行されるかを指定します。この行は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: ここに指定したグループ名（例: &lt;code&gt;taku&lt;/code&gt;）のグループID（GID）に切り替えてサービスを実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;具体例&lt;/strong&gt;: &lt;code&gt;Group=yourusername&lt;/code&gt;と指定した場合、VNCサーバーは&lt;code&gt;yourusername&lt;/code&gt;ユーザーのプライマリグループとして動作します。通常は&lt;code&gt;User&lt;/code&gt;と同じユーザー名を指定します。この行を省略すると、指定されたユーザーのプライマリグループが自動的に適用されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;注意点&lt;/strong&gt;: ここには&lt;strong&gt;必ずシステムに存在するグループ名&lt;/strong&gt;を指定してください。存在しないグループ名を指定すると、サービスは起動に失敗します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/yourusername&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、systemdがこのサービスを起動する際に、どのディレクトリを「作業ディレクトリ」とするかを指定しています。この行は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: ここに指定したディレクトリ（例: &lt;code&gt;/home/yourusername&lt;/code&gt;）が、サービス内でコマンドが実行される際の基準となります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;具体例&lt;/strong&gt;: VNCサーバーのログファイル（&lt;code&gt;~/.vnc/hostname:2.log&lt;/code&gt;など）はユーザーのホームディレクトリ内に作成されるため、この設定でVNCサービスがユーザーのホームディレクトリを基準に動作していることを明確にします。省略した場合、デフォルトの作業ディレクトリは通常 &lt;code&gt;/&lt;/code&gt; (ルートディレクトリ) になります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStartPre&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/sh -c &lt;span class="s1"&gt;&amp;#39;/usr/bin/vncserver -kill :2 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 || :&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、サービスが起動するメインのコマンド（ExecStart）を実行する直前に実行されるコマンドを指定します。この項目は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: &lt;code&gt;systemd&lt;/code&gt;はサービスを起動する前に、&lt;code&gt;/usr/bin/vncserver -kill :2&lt;/code&gt;コマンドを実行します。これは、&lt;strong&gt;もし同じディスプレイ番号（&lt;code&gt;:2&lt;/code&gt;）でVNCサーバーが既に動いていたら、それを強制的に終了させる&lt;/strong&gt;ためのものです。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;具体例&lt;/strong&gt;: 以前VNCサーバーがクラッシュして残骸が残っていたり、誤って手動でVNCサーバーを起動してしまったりした場合など、起動を妨げる可能性のある古いVNCセッションを「お掃除」してくれます。&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;&amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;/code&gt;: この部分で、&lt;code&gt;vncserver -kill&lt;/code&gt;コマンドが画面に出力するメッセージ（例: 「VNCサーバーを終了しました」）を非表示にします。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;|| :&lt;/code&gt;: この部分は、もし&lt;code&gt;vncserver -kill&lt;/code&gt;コマンドが失敗しても（例: そもそもVNCサーバーが動いていなかった場合など）、&lt;code&gt;systemd&lt;/code&gt;がこのステップでエラーを吐かずに、次の&lt;code&gt;ExecStart&lt;/code&gt;に進むようにするためのシェルスクリプトの記法です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/vncserver -localhost no :2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、サービスが起動する際に systemd が実行するメインのコマンドを指定します。この項目は必須です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: &lt;code&gt;/usr/bin/vncserver&lt;/code&gt;コマンドを、以下のオプションを付けて実行します。&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-localhost no&lt;/code&gt;: 他のコンピューター（Macなど）からのVNC接続を許可します。これを設定しないと、同じLinuxマシンからしか接続できません。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;:2&lt;/code&gt;: VNCサーバーを&lt;strong&gt;ディスプレイ番号2&lt;/strong&gt;で起動します。これにより、VNCクライアントからはポート番号 &lt;strong&gt;&lt;code&gt;5902&lt;/code&gt;&lt;/strong&gt; を使って接続することになります（VNCはポート &lt;code&gt;5900 + ディスプレイ番号&lt;/code&gt; を使用するため）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/vncserver -kill :2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、サービスが停止される際に systemd が実行するコマンドを指定します。この項目は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: サービスを停止するときに、&lt;code&gt;/usr/bin/vncserver -kill :2&lt;/code&gt;コマンドを実行し、指定されたディスプレイ番号のVNCサーバープロセスを終了させます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;: サービスを安全に終了させ、関連するプロセスをクリーンアップするために使用されます。&lt;code&gt;systemd&lt;/code&gt;は、このコマンドがエラーなく終了した場合に、サービスが正常に停止したと判断します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;実行される条件&lt;/strong&gt;:&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;systemctl stop vncserver_yourusername.service&lt;/code&gt;と明示的に停止コマンドを実行したとき。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;systemctl restart vncserver_yourusername.service&lt;/code&gt;を実行し、サービスが起動していた場合。&lt;/li&gt;&#10;&lt;li&gt;システムシャットダウン時または再起動時、サービスが起動していた場合。&lt;/li&gt;&#10;&lt;li&gt;サービスが属する「ターゲット」が停止されたり、システムの動作レベルが変更されたりした場合。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;実行されないケース&lt;/strong&gt;:&#10;&lt;ol&gt;&#10;&lt;li&gt;サービスが一度も正常に起動しなかった場合。&lt;/li&gt;&#10;&lt;li&gt;サービスプロセスが&lt;code&gt;systemd&lt;/code&gt;の関与なしにクラッシュしたり、&lt;code&gt;kill -9&lt;/code&gt;のような強制終了コマンドで外部から終了させられたりした場合。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="install-セクション"&gt;&lt;code&gt;[Install]&lt;/code&gt; セクション&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Install&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、systemdサービスファイルの別のセクションの開始を示す見出しです。このセクションは任意です。このセクションは、systemctl enableコマンドが実行されたときにのみ参照されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、systemctl enableコマンドが実行された際に、このサービスをどの「ターゲット」に紐付けるかを指定します。この項目は任意です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;意味&lt;/strong&gt;: &lt;code&gt;multi-user.target&lt;/code&gt;は、&lt;code&gt;systemd&lt;/code&gt;が定義する &lt;strong&gt;「ネットワークが利用可能で、複数のユーザーがログインできる状態」（GUIなしのサーバーモードに相当）&lt;/strong&gt; を示す標準的なターゲットです。これは古いLinuxの「ランレベル3」に相当します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;: この行があることで、&lt;code&gt;systemctl enable vncserver_yourusername.service&lt;/code&gt;を実行すると、システムが&lt;code&gt;multi-user.target&lt;/code&gt;の状態になったときに、このサービスが自動的に起動するように設定されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;注意点&lt;/strong&gt;: この行を設定しないと、&lt;code&gt;systemctl enable&lt;/code&gt;コマンドはエラーとなり、システム起動時に自動的にサービスが起動しません。手動で&lt;code&gt;systemctl start&lt;/code&gt;コマンドを実行することは可能です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="vncサーバー自動起動設定の手順-まとめ"&gt;VNCサーバー自動起動設定の手順 (まとめ)&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCパスワードの設定&lt;/strong&gt;: ターミナルで &lt;code&gt;vncpasswd&lt;/code&gt; と入力し、VNC接続用のパスワードを設定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ファイアウォール（UFW）の開放&lt;/strong&gt;: Bash&lt;code&gt;sudo ufw allow 5902/tcp sudo ufw enable sudo ufw status verbose # 設定が反映されたか確認&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCサーバーサービスファイルの作成と保存&lt;/strong&gt;: &lt;code&gt;yourusername&lt;/code&gt;の部分を、VNCセッションで使いたいユーザー名に置き換えてください。 Bash&lt;code&gt;sudo nano /etc/systemd/system/vncserver_yourusername.service&lt;/code&gt; 上記の「サービスファイルの内容」を貼り付けて保存します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;systemd&lt;/code&gt; の設定を再読み込み&lt;/strong&gt;: Bash&lt;code&gt;sudo systemctl daemon-reload&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCサービスを自動起動可能にする（有効化）&lt;/strong&gt; : Bash&lt;code&gt;sudo systemctl enable vncserver_yourusername.service&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCサービスを今すぐ起動&lt;/strong&gt;: Bash&lt;code&gt;sudo systemctl start vncserver_yourusername.service&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;サービスのステータスを確認&lt;/strong&gt;: Bash&lt;code&gt;sudo systemctl status vncserver_yourusername.service&lt;/code&gt; 出力の中に &lt;code&gt;Active: active (running)&lt;/code&gt; と表示されれば成功です。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;これで、あなたのLinuxシステムが起動するたびに、VNCサーバーが自動的に立ち上がるようになります。 &lt;code&gt;vnc://&amp;lt;LinuxのIPアドレス&amp;gt;:5902&lt;/code&gt; で接続して、快適なリモート操作を始めましょう！&lt;/p&gt;&#10;</description></item><item><title>MacからPop!_OSをリモート操作！TigerVNCサーバー設定完全ガイド</title><link>https://ai.hack-le.com/mac-pop_os-tigervnc/</link><pubDate>Sun, 22 Jun 2025 15:26:50 +0900</pubDate><guid>https://ai.hack-le.com/mac-pop_os-tigervnc/</guid><description>&lt;p&gt;Pop!_OSをクリーンインストールしたばかりでリモートから操作したい、またはMacからLinuxデスクトップを快適に使いたいと考えていませんか？この記事では、macOSからPop!_OS 22.04 (GNOMEベース) へVNC接続するための手順を、つまづきやすいポイントも含めて詳しく解説します。&lt;/p&gt;&#10;&lt;p&gt;Splashtopのような商用ツールも便利ですが、VNCを使えば同じLAN内なら無料で、しかもMacに標準搭載されている機能でリモートデスクトップが可能です。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="はじめにvncって何"&gt;はじめに：VNCって何？&#10;&lt;/h2&gt;&lt;p&gt;VNC (Virtual Network Computing) は、ネットワーク経由で別のコンピューターのデスクトップ画面を操作するための技術です。サーバー側のPCにVNCサーバーソフトウェアを、クライアント側のPCにVNCクライアントソフトウェアをインストールすることで、リモート操作が可能になります。&lt;/p&gt;&#10;&lt;p&gt;今回のケースでは、Pop!_OSがVNCサーバー、MacがVNCクライアントになります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCサーバー側 (Pop!_OS)&lt;/strong&gt; : Pop!_OS 22.04 LTS (GNOMEデスクトップ環境がインストール済みであること)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCクライアント側 (Mac)&lt;/strong&gt; : macOS 14.6.1 (Mac mini M2 Pro)&lt;/li&gt;&#10;&lt;li&gt;両方のPCが同じローカルネットワーク（LAN）に接続されていること&lt;/li&gt;&#10;&lt;li&gt;Pop!_OSのIPアドレスが分かっていること (例: &lt;code&gt;192.168.0.161&lt;/code&gt;)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="step-1-pop_osへのtigervncサーバーとxfce4のインストール"&gt;Step 1: Pop!_OSへのTigerVNCサーバーとXFCE4のインストール&#10;&lt;/h2&gt;&lt;p&gt;Pop!_OSのデフォルトデスクトップ環境であるGNOME Shellは、TigerVNCサーバーと直接連携するのが難しい場合があります。そのため、VNCセッション用に軽量で互換性の高い&lt;strong&gt;XFCE4デスクトップ環境&lt;/strong&gt;を導入することをおすすめします。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;システムを最新の状態に更新します。&lt;/strong&gt; Bash&lt;code&gt;sudo apt update sudo apt upgrade -y&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;TigerVNCサーバーとXFCE4デスクトップ環境、およびLightDMをインストールします。LightDMは、VNCセッションがデスクトップ環境を適切に起動するのに役立つことがあります。 Bash&lt;code&gt;sudo apt install tigervnc-standalone-server tigervnc-xorg-extension xfce4 xfce4-goodies lightdm -y&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;インストール中、デフォルトディスプレイの選択が出ます。ここではlightdmではなく、gdmのままとします。物理デスクトップとVNCセッションで異なるデスクトップ環境を使うことで、それぞれのセッションが干渉し合うリスクを減らせます。&lt;/p&gt;&#10;&lt;p&gt;もしlghtdmを選択してしまった場合、 &lt;code&gt;sudo dpkg-reconfigure gdm3&lt;/code&gt;で戻すことができます。ログイン画面においても、Ctrl + Alt + F3でターミナルに切り替えて実行できます。&lt;/p&gt;&#10;&lt;p&gt;もしxfce4とLightDMが不要であれば、以下でアンインストールできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt purge xfce4 xfce4-goodies lightdm -y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt autoremove -y&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-vncパスワードの設定とサーバーの起動"&gt;Step 2: VNCパスワードの設定とサーバーの起動&#10;&lt;/h2&gt;&lt;p&gt;VNC接続に必要なパスワードを設定し、VNCサーバーを起動します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;VNCパスワードを設定します。ターミナルで次のコマンドを実行し、VNC接続用のパスワードを設定してください。これは、通常のシステムパスワードとは別で、VNC接続時にのみ使用します。 Bash&lt;code&gt;vncpasswd&lt;/code&gt; 「Verify」と表示されたら、確認のためにもう一度同じパスワードを入力します。Would you like to enter a view-only password (y/n)? と聞かれたら、通常は「n」で問題ありません。&lt;/li&gt;&#10;&lt;li&gt;VNCサーバーを起動します。ここで重要なのが、外部からの接続を許可するオプションである -localhost no を追加することです。これを忘れると、Macから接続しようとしたときに「Connection refused」というエラーが発生します。ディスプレイ番号は :1 (ポート5901) や :2 (ポート5902) など、未使用のものを選択します。ここでは例として :2 を使います。 Bash&lt;code&gt;vncserver -localhost no :2&lt;/code&gt; &lt;code&gt;New Xtigervnc server 'pop-os:2 (taku)' on port 5902 for display :2.&lt;/code&gt; のようなメッセージが表示されれば、VNCサーバーは正常に起動しています。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="step-3-vncセッションでxfce4を起動するための設定-vncxstartup"&gt;Step 3: VNCセッションでXFCE4を起動するための設定 (&lt;code&gt;~/.vnc/xstartup&lt;/code&gt;)&#10;&lt;/h2&gt;&lt;p&gt;VNCサーバーが起動しても、どのデスクトップ環境を表示するかを指示する必要があります。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;現在起動しているVNCサーバーを一度停止します。&lt;/strong&gt; Bash&lt;code&gt;vncserver -kill :2&lt;/code&gt; &lt;code&gt;Killing Xtigervnc server on display :2 ... success!&lt;/code&gt; のようなメッセージが表示されるはずです。&lt;/li&gt;&#10;&lt;li&gt;~/.vnc/xstartup ファイルを編集します。このファイルは、vncserver コマンドを初めて実行したときに自動生成されますが、デフォルトのままではGNOME Shellがうまく起動しないことがあります。XFCE4を起動するように内容を修正します。 Bash&lt;code&gt;nano ~/.vnc/xstartup&lt;/code&gt; ファイルの中身を&lt;strong&gt;すべて削除&lt;/strong&gt;し、&lt;strong&gt;以下の3行を正確に貼り付けてください。&lt;/strong&gt; Bash&lt;code&gt;#!/bin/bash unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS startxfce4&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;#!/bin/bash&lt;/code&gt;: スクリプトがBashシェルで実行されることを指定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;unset SESSION_MANAGER&lt;/code&gt; と &lt;code&gt;unset DBUS_SESSION_BUS_ADDRESS&lt;/code&gt;: デスクトップセッションの競合を防ぐための重要な設定です。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;startxfce4&lt;/code&gt;: VNCセッション内でXFCE4デスクトップ環境を起動するコマンドです。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;ファイルを保存してエディタを終了します。Nanoの場合: Ctrl + O を押して保存 → Enter でファイル名を確定 → Ctrl + X でエディタを終了します。&lt;/li&gt;&#10;&lt;li&gt;xstartupファイルに実行権限があることを確認します。通常は設定されていますが、念のため実行しておきましょう。 Bash&lt;code&gt;chmod +x ~/.vnc/xstartup&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCサーバーを再度起動します。&lt;/strong&gt; Bash&lt;code&gt;vncserver -localhost no :2&lt;/code&gt; これでVNCセッション内でXFCE4デスクトップが起動する準備が整いました。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="step-4-ファイアウォール-ufw-の設定"&gt;Step 4: ファイアウォール (UFW) の設定&#10;&lt;/h2&gt;&lt;p&gt;Pop!_OSには&lt;code&gt;ufw&lt;/code&gt;というファイアウォールが標準で含まれており、外部からの接続をブロックしています。VNC接続を許可するために、VNCサーバーが使用するポートを開放する必要があります。&lt;/p&gt;&#10;&lt;p&gt;VNCサーバーはディスプレイ番号に5900を足したポートを使用します。今回はディスプレイ&lt;code&gt;:2&lt;/code&gt;なので、ポートは&lt;code&gt;5902&lt;/code&gt;です。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCポート (5902) を許可するルールを追加します。&lt;/strong&gt; Bash&lt;code&gt;sudo ufw allow 5902/tcp&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;UFWが有効になっていることを確認します。&lt;/strong&gt; Bash&lt;code&gt;sudo ufw enable&lt;/code&gt; &lt;code&gt;ファイアウォールはアクティブかつシステムの起動時に有効化されます。&lt;/code&gt; のようなメッセージが表示されればOKです。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;UFWのステータスを確認し、ルールが正しく追加されたか確認します。&lt;/strong&gt; Bash&lt;code&gt;sudo ufw status verbose&lt;/code&gt; 出力に &lt;code&gt;5902/tcp ALLOW IN Anywhere&lt;/code&gt; のような行があれば成功です。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="step-5-macからpop_osへvnc接続"&gt;Step 5: MacからPop!_OSへVNC接続&#10;&lt;/h2&gt;&lt;p&gt;これでPop!_OS側の設定は完了です。MacからVNC接続を試みましょう。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;MacのFinderを開きます。&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「サーバへ接続」ウィンドウを開きます。&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;画面上部のメニューバーで「&lt;strong&gt;移動&lt;/strong&gt;」をクリックし、ドロップダウンメニューから「&lt;strong&gt;サーバへ接続&amp;hellip;&lt;/strong&gt; 」を選択します。（または、ショートカットキー &lt;code&gt;⌘ + K&lt;/code&gt; を押します）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;VNCアドレスを入力します。開いたウィンドウのアドレス欄に、以下のように入力します。 &lt;code&gt;vnc://&amp;lt;Pop!_OSのIPアドレス&amp;gt;:5902&lt;/code&gt; 例：Pop!_OSのIPアドレスが &lt;code&gt;192.168.0.161&lt;/code&gt; の場合、&lt;code&gt;vnc://192.168.0.161:5902&lt;/code&gt; と入力します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「接続」ボタンをクリックします。&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;VNCパスワードを入力します。VNCパスワードの入力を求められたら、Step 2で設定したパスワードを入力し、「サインイン」をクリックします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;これで、Macの画面にPop!_OSのXFCE4デスクトップが表示されるはずです。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="トラブルシューティングもし接続できない場合"&gt;トラブルシューティング：もし接続できない場合&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;「Connection refused」エラーがMac側で出る場合&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;li&gt;最も可能性が高いのは、Step 2でVNCサーバーを起動する際に &lt;code&gt;-localhost no&lt;/code&gt; オプションを付け忘れたことです。&lt;code&gt;vncserver -kill :2&lt;/code&gt; でサーバーを停止し、&lt;code&gt;vncserver -localhost no :2&lt;/code&gt; で再起動してください。&lt;/li&gt;&#10;&lt;li&gt;Pop!_OSのターミナルで &lt;code&gt;nc -vz 127.0.0.1 5902&lt;/code&gt; と &lt;code&gt;nc -vz &amp;lt;Pop!_OSのIPアドレス&amp;gt; 5902&lt;/code&gt; を実行し、両方で &lt;code&gt;succeeded!&lt;/code&gt; となるか確認してください。後者が &lt;code&gt;Connection refused&lt;/code&gt; なら上記 &lt;code&gt;-localhost no&lt;/code&gt; が原因です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;画面が真っ黒/灰色、またはログイン画面が表示されない場合&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Step 3の &lt;code&gt;~/.vnc/xstartup&lt;/code&gt; ファイルの内容が間違っている可能性が高いです。特に &lt;code&gt;startxfce4&lt;/code&gt; が正しく記述されているか、余計な行が残っていないか再確認してください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;VNCサーバーが起動していないか確認&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Pop!_OSのターミナルで &lt;code&gt;ps aux | grep vnc&lt;/code&gt; を実行し、&lt;code&gt;Xtigervnc&lt;/code&gt; のプロセスが動いているか確認します。表示されない場合は、&lt;code&gt;vncserver -localhost no :2&lt;/code&gt; で再度起動してください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;IPアドレスの入力ミス&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Macの接続ダイアログで、Pop!_OSのIPアドレスを正確に入力しているか再確認してください。Pop!_OS側で &lt;code&gt;ip a&lt;/code&gt; コマンドで確認できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="自動起動"&gt;自動起動&#10;&lt;/h2&gt;&lt;p&gt;シングルユーザの場合。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;/etc/system/systemd/vncserver.service&lt;/code&gt;に以下を記述（sudo権限でemacsなりnanoなりviなり好きなので）。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Remote desktop service &lt;span class="o"&gt;(&lt;/span&gt;VNC&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;network.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;forking&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ユーザ&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;グループ&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/ユーザ&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/vncserver -localhost no :2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/vncserver -kill :2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Install&lt;span class="o"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ユーザとグループのところを置き換える。ExecStartのところが起動コマンド。マルチユーザならUserのところは置き換えられるように &lt;code&gt;%i&lt;/code&gt; とかにする必要あり。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl daemon-reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; vncserver.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl start vncserver.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;マルチユーザのときは &lt;code&gt;vncserver@&amp;lt;user&amp;gt;.service&lt;/code&gt;とすると@以降が&lt;code&gt;%i&lt;/code&gt;で置き換わるはず（試してない）。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://gist.github.com/spinxz/1692ff042a7cfd17583b" target="_blank" rel="noopener"&#10; &gt;systemd service file for running a vncserver (e.g. tightvncserver)&lt;/a&gt;にあるように事故防止で &lt;code&gt;ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 || :'&lt;/code&gt;は入れておいてもいいかも。一人用だから入れてないけど。&lt;/p&gt;&#10;</description></item><item><title>スティーブ・ジョブズのAndroidへの怒りとスマートフォン業界への影響</title><link>https://ai.hack-le.com/%E3%82%B9%E3%83%86%E3%82%A3%E3%83%BC%E3%83%96%E3%83%BB%E3%82%B8%E3%83%A7%E3%83%96%E3%82%BA%E3%81%AEandroid%E3%81%B8%E3%81%AE%E6%80%92%E3%82%8A%E3%81%A8%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%83%95/</link><pubDate>Mon, 12 May 2025 00:28:17 +0900</pubDate><guid>https://ai.hack-le.com/%E3%82%B9%E3%83%86%E3%82%A3%E3%83%BC%E3%83%96%E3%83%BB%E3%82%B8%E3%83%A7%E3%83%96%E3%82%BA%E3%81%AEandroid%E3%81%B8%E3%81%AE%E6%80%92%E3%82%8A%E3%81%A8%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%83%95/</guid><description>&lt;p&gt;2007年1月、ジョブズはiPhoneを発表しスマートフォン市場を一変させた。これに衝撃を受けたGoogleのモバイルチームは、従来計画していたAndroid携帯（通称「Sooner」）を撤回し、新たにマルチタッチ対応デバイスの開発に着手したという。こうして2007年末にAndroid OSが発表されると、ジョブズはAndroidを「盗作（stolen product）」と看做して激しく反発するようになる。ウォルター・アイザックソンの伝記によれば、ジョブズはAndroid搭載機の登場後に「最後の一息まで戦う」「Androidを壊してやる、そのためなら熱核戦争も厭わない」と怒りを露わにし、Google製品を「（iPhoneに対して）めちゃくちゃコピーした」と罵倒した。彼は金銭の譲歩ではなく、ただ「我々のアイデアをAndroidで使うのをやめてくれ」とシュミット氏に求めたとも伝えられている。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://www.reuters.com/article/lifestyle/key-excerpts-from-steve-jobs-biography-idUSTRE79N75M/" target="_blank" rel="noopener"&#10; &gt;Key excerpts from &amp;ldquo;Steve Jobs&amp;rdquo; biography | Reuters&lt;/a&gt;も示すように、当初ジョブズとGoogleの関係は良好だった。2006年にはGoogleのエリック・シュミットCEOがAppleの取締役に迎えられ、両社は検索や地図サービスで協力していた。しかしiPhoneの成功に伴い競争が激化し、2008年にはジョブズがGoogle本社でラリー・ペイジらと激論したという逸話が伝わる。2009年8月にはシュミットCEOが社内声明で辞任を表明し、「AndroidやChrome OSの登場でAppleの中核ビジネスへの関与が著しく制限される」とジョブズは声明で説明している。こうして相互の信頼関係は崩れ、AppleとGoogleは競合関係へと転じた。&lt;/p&gt;&#10;&lt;p&gt;特許紛争も激化した。2010年3月、AppleはHTCを皮切りにAndroid陣営への訴訟を開始した。これを機にジョブズはIsaacson氏へのインタビューで「Androidは盗作であり、すべてを投入してでも戦う」と宣言し、「Androidを破壊する。熱核戦争も厭わない」とまで語った。さらに同年末にはモトローラ、2011年にはSamsungも訴訟対象となり、世界中でApple対Android各社の「スマホ特許戦争」が展開された。Appleはドイツなどで「スライドしてロック解除」（slide-to-unlock）機能の差し止め命令を勝ち取り、Samsungのタブレット製品デザイン変更を迫るなど一定の成果を挙げた。&lt;/p&gt;&#10;&lt;p&gt;技術面でもAppleは独自色を打ち出した。ジョブズはユーザー体験を重視し、iPhoneの特徴的なUI機能に積極的に特許を取得させた。たとえば、iOSの画面端で表示を跳ね返す「ゴムバンド効果」はUS特許“’381”で保護されているが、iOS開発責任者Forstall氏は「ゴムバンド効果はiPhoneの流麗さの肝で、ジョブズが非常に重視していた」と証言している。またForstall氏によれば、ジョブズはSamsungに対し「これは我々が発明したものだ。マネするな、盗むな」と直接述べたという。AppleはこうしたUI特許を武器に、競合機種のデザインや操作に類似性が見られるたびに法廷闘争を仕掛けた。さらにAppleは、自社の閉じたエコシステムを軸にハードウェアとソフトウェアの統合設計を強化し、iOS機能やSiriなど差別化要素を次々と追加した。ジョブズは「我々はコントロール重視だからではなく素晴らしい製品を作るためにこうする」と述べ、Androidのオープン志向との対比を明確にしていた。&lt;/p&gt;&#10;&lt;p&gt;その結果、AppleとGoogleはスマートフォンOSの二大勢力として対峙する形となった。ジョブズはAndroidを「めちゃくちゃな出来」と評し、Appleは「素晴らしい製品を作る」ことに専念する道を選んだ。現在、Androidは世界のスマホOSシェアの約7割を占めている一方、AppleのiOSも米国市場では5割以上のシェアを維持している。この対立はまた、スマホ業界全体に知的財産権の扱いに関する議論を呼び起こした。Apple対Androidの紛争は「インスピレーションと模倣の境界」を問う事例となり、以降のモバイル競争に長期的な影響を与えている。&lt;/p&gt;&#10;</description></item><item><title>Vivaldiブラウザの誕生背景</title><link>https://ai.hack-le.com/vivaldi%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E8%AA%95%E7%94%9F%E8%83%8C%E6%99%AF/</link><pubDate>Mon, 12 May 2025 00:20:01 +0900</pubDate><guid>https://ai.hack-le.com/vivaldi%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E8%AA%95%E7%94%9F%E8%83%8C%E6%99%AF/</guid><description>&lt;p&gt;Vivaldiは、かつてOpera SoftwareのCEOを務めたJon von Tetzchner氏が、Operaの開発方針変更やユーザーコミュニティ（「My Opera」）の閉鎖に反発して立ち上げたブラウザです。2014年3月にOpera公式フォーラム「My Opera」が閉鎖されると、Tetzchner氏は同年1月に代替コミュニティサイト「Vivaldi.net」を立ち上げ、2015年1月27日には技術プレビュー版のVivaldiブラウザを公開、翌2016年4月にバージョン1.0の正式版をリリースしました。創設の動機について氏は「既存の主要ブラウザはユーザーの声を十分に反映しておらず、自分が欲しいブラウザは存在しなかった」と語っており、多機能かつカスタマイズ性の高いOpera（Prestoエンジン時代）で好評だった機能を、Chromiumベースでも復活させることを目指しました。特に旧Operaユーザーやハイテク志向のパワーユーザーに支持される“ユーザー第一主義”ブラウザとして位置づけられています。&lt;/p&gt;&#10;&lt;h2 id="技術的特徴"&gt;技術的特徴&#10;&lt;/h2&gt;&lt;p&gt;VivaldiはエンジンにChromium（Blink）を用いながら、&lt;strong&gt;独自UIレイヤー&lt;/strong&gt;をHTML/CSS/JavaScriptで構築している点が特徴です。UIのほとんどはWeb技術で実装されており、テーマや配色、タブの配置などを柔軟にカスタマイズできます。ただしこのUI部分はクローズドソース（約5%）で公開されています。Vivaldiには豊富な組み込み機能があります。例えば -&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;タブ管理機能&lt;/strong&gt;：タブをグループ化する「タブスタック」や画面分割「タイル表示」が可能で、使わないタブは休止（ヒベナート）してメモリ消費を抑制できる。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;マウスジェスチャー&lt;/strong&gt;：タブ移動やページ操作などをマウス動作だけで実行できる。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Webパネル&lt;/strong&gt;：サイドバーに任意のWebページを常駐表示する機能で、参照サイトやツールを常に表示できる。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;メモ／アノテーション&lt;/strong&gt;：Webページ上に手書きメモやスクリーンショットを追加し、閲覧履歴とともに管理可能。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;統合メール・フィードリーダー&lt;/strong&gt;：IMAP/POP対応のメールクライアント（Vivaldi Mail）とRSS/Atomフィードリーダーを標準搭載。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;カレンダー・翻訳&lt;/strong&gt;：組み込みカレンダーでイベント管理ができ、Webページ翻訳（Lingvanex）機能も内蔵。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;プライバシー機能&lt;/strong&gt;：広告ブロックやトラッカー防止機能を標準搭載。さらに2025年3月には&lt;strong&gt;Proton VPN&lt;/strong&gt;のデスクトップ版組み込みが発表され、追加設定なしにVPN接続が利用可能になりました（図）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Vivaldiデスクトップ版には2025年3月にProton VPNがネイティブ統合され、追加インストール不要でVPN接続が可能となった。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;その他の機能&lt;/strong&gt;：ブックマークのショートカットを並べる「スピードダイヤル」、設定や履歴を検索できる「クイックコマンド」、Chrome/Firefox用拡張機能のほとんどが使用可能（UIはChromiumと異なるためChrome専用テーマは非対応）、透明UI（Chromeless）モードなど、多機能かつ高度にカスタマイズ可能な設計となっています。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="現在の市場シェア普及状況"&gt;現在の市場シェア・普及状況&#10;&lt;/h2&gt;&lt;p&gt;市場規模ではVivaldiの占有率は極めて小規模です。StatCounterなどの統計ではGoogle ChromeやSafari、Edgeに次ぐカテゴリ外に含まれ、グローバルデスクトップシェアは&lt;strong&gt;約0.2%&lt;/strong&gt; とされます（ちなみにChromeは約64%、Edge約13%）。またVivaldiはユーザーエージェントをChromiumの一般ビルドに偽装する設定にしており、実際の利用者がChromeにカウントされてしまうため、市場シェアの計測でも「その他」に分類される傾向があります。&lt;/p&gt;&#10;&lt;p&gt;公式発表では、2024年末時点で&lt;strong&gt;アクティブユーザー数は310万人&lt;/strong&gt;を超えており、Android版はGoogle Playで累計500万件以上インストールされています。利用者層としては機能を求める技術志向ユーザーが多く、旧Operaユーザーやカスタマイズ好きが中心です。統計上の傾向では、Vivaldi関連サイトへのアクセスの約59%が日本からであり、ユーザーの約72.7%は男性、年齢層では25–34歳が最も多い（約28.0%）と報告されています。日本やアジア圏での人気が高い点も特徴です。なおプラットフォーム別では、PC版が2015年、Android版が2019年、そして&lt;strong&gt;iOS版は2023年9月&lt;/strong&gt;にようやく正式リリースされました。&lt;/p&gt;&#10;&lt;h2 id="今後の展望"&gt;今後の展望&#10;&lt;/h2&gt;&lt;p&gt;Vivaldiは豊富な独自機能で差別化を図る一方、市場シェア拡大には大きな制約があります。業界では「多機能ぶんだけ初心者には敷居が高い」「競合大手との差を埋めるのは容易ではない」との見方が強く、実際初期レビューでも“ニッチなブラウザであり続ける”と指摘されています。Chrome/Safari/Edgeら独占状態の現在、Vivaldiが大衆的なシェアを獲得するには相当の時間と投資を要します。&lt;/p&gt;&#10;&lt;p&gt;それでもVivaldiは当面、&lt;strong&gt;コアユーザー層を大切にした独自戦略&lt;/strong&gt;で生き残りを目指します。高いカスタマイズ性やプライバシー重視機能、統合メールなど独自サービスが強みで、最近ではProton VPNの組込みでプライバシー強化に注力しています。またiOS版や車載版（Android Automotive向け）などモバイル・新プラットフォームへの展開で認知拡大を図っており、従来のPCブラウザに留まらない利用シーン拡大を狙っています。一方、開発リソースはNorway/アイスランド/米国に拠点を置く約50名規模の小所帯で、外部投資を受けず社員持株制で運営されているため、資金・人員面で限界もあります。収益モデルは検索エンジン提携による検索連携収入が中心であり、広告やユーザーデータ収益化を行わない方針です。このため大規模なマーケティングや機能開発投資は難しく、AI機能実装など今後の機能追加にも制約があると考えられます。&lt;/p&gt;&#10;&lt;p&gt;中長期的には、Vivaldiは&lt;strong&gt;ニッチ戦略&lt;/strong&gt;を堅持しつつ徐々に浸透を図ることになるでしょう。競合との差別化要素（高度なタブ管理、高度カスタマイズ、統合ツール群など）を維持しながら、プライバシー志向市場や技術志向ユーザーを取り込む狙いです。一方で、市場の大勢は変え難いため、シェア拡大は緩やかに留まる可能性が高いと見られています。今後の課題としては、限られた人員で製品開発を続ける一方、増え続けるユーザーニーズにどう対応するかが問われます。総じて、Vivaldiはコアな支持層を背景に堅調な成長を目指すものの、Chromeらと張り合う大規模ブラウザになるのは難しく、あくまで機能重視のニッチ市場戦略を続ける形となりそうです。&lt;/p&gt;&#10;</description></item><item><title>Firefoxの市場シェアの推移と盛衰</title><link>https://ai.hack-le.com/firefox%E3%81%AE%E5%B8%82%E5%A0%B4%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%AE%E6%8E%A8%E7%A7%BB%E3%81%A8%E7%9B%9B%E8%A1%B0/</link><pubDate>Mon, 12 May 2025 00:09:53 +0900</pubDate><guid>https://ai.hack-le.com/firefox%E3%81%AE%E5%B8%82%E5%A0%B4%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%AE%E6%8E%A8%E7%A7%BB%E3%81%A8%E7%9B%9B%E8%A1%B0/</guid><description>&lt;p&gt;Mozilla Firefoxは2004年に正式版が公開されたオープンソースのウェブブラウザです。Internet Explorer（以下、IE）が独占的だった市場に挑み、登場当初は高速な表示、タブブラウジングや拡張機能によるカスタマイズ性の高さなどが評価されました。一時は世界シェア約3割に達しIEの牙城を崩しましたが、2008年に登場したGoogle Chromeとの競争を経て次第に勢いを失い、2020年代には一桁台のシェアにまで落ち込んでいます。本レポートでは、Firefoxの2000年代前半から2025年までの市場シェアの推移を振り返り、その盛衰の背景を、競合ブラウザとの関係、技術革新、Mozillaの収益構造や提携、ユーザー層とブランドイメージの変化といった観点から時系列で分析します。&lt;/p&gt;&#10;&lt;h2 id="2000年代前半ie独占への挑戦と急成長"&gt;2000年代前半：IE独占への挑戦と急成長&#10;&lt;/h2&gt;&lt;p&gt;2000年代前半、ウェブブラウザ市場はMicrosoftのIEが支配的で、そのシェアは90%以上に及んでいました。しかしIE6は2001年のリリース以降長らく大きな更新がなく、セキュリティ面の不安や技術的陳腐化が指摘されていました。こうした中、Netscape由来のオープンソースプロジェクトであるMozillaは「Mozilla Application Suite」からブラウザ部分を独立させ、軽量化した新ブラウザを開発します。それが&lt;strong&gt;Firefox&lt;/strong&gt;であり、2002年にプレリリース版（コードネーム「Phoenix」）が公開、2004年11月に正式版1.0がリリースされました。&lt;/p&gt;&#10;&lt;p&gt;Firefoxは当初から技術コミュニティや上級ユーザーの支持を集め、IEにはない&lt;strong&gt;タブブラウズ&lt;/strong&gt;や豊富な&lt;strong&gt;拡張機能&lt;/strong&gt;によるカスタマイズ、そして悪名高いActiveXを避けた堅牢な&lt;strong&gt;セキュリティ&lt;/strong&gt;などが評価されました。リリースから9か月で6000万回以上ダウンロードされるなど爆発的なスタートを切り、シェアも着実に伸ばしていきます。2007年時点でFirefoxは世界シェア約10％台に達し、特に欧州では24％超と高い支持を得ていました。2008年にはついに&lt;strong&gt;世界シェア20％&lt;/strong&gt; を突破し、IEの独占体制を崩す大きな節目となりました。この頃にはIEのシェアも約70％前後まで低下しており（2004年は90％超）、Firefoxは名実ともにIEに次ぐ第二のブラウザとして定着します。また同時期、AppleのSafari（2003年登場、主にMacと2007年発売のiPhoneで普及）やOperaなど他のブラウザも存在しましたが、シェア面ではFirefoxがIE打倒の筆頭格でした。&lt;/p&gt;&#10;&lt;p&gt;技術面では、Firefoxはオープンウェブ標準の推進役ともなり、IEに実装の遅れていたCSSやSVGといった標準をいち早くサポートしました。拡張機能では広告ブロックや開発者向けツール（Firebugなど）が人気を博し、ユーザー主導の機能拡張文化が育まれました。また、Mozillaは非営利団体でありつつも経営面で&lt;strong&gt;検索エンジンからの収入&lt;/strong&gt;に支えられていました。Firefoxの検索デフォルトは当初よりGoogleで、GoogleからのロイヤルティがMozilla財団収入の大部分を占めていました（例えば2014年にはMozillaの総収入3億30百万ドルのうち3億23百万ドルをGoogleとの提携が占めました）。もっとも2000年代後半までは、GoogleはMozillaにとって支援者でしたが後に強力な競合相手ともなります。&lt;/p&gt;&#10;&lt;h2 id="20082011年chromeの台頭と逆転劇"&gt;2008〜2011年：Chromeの台頭と逆転劇&#10;&lt;/h2&gt;&lt;p&gt;2008年9月、検索大手のGoogleが満を持して独自ブラウザ&lt;strong&gt;Chrome&lt;/strong&gt;をリリースします。Chromeは高速JavaScriptエンジン「V8」やマルチプロセスアーキテクチャによる安定性を武器に、シンプルで軽快なユーザー体験を提供しました。さらにGoogleは自社の検索サイトや各種広告枠を通じてChromeを大々的に宣伝し、ユーザー獲得を推進します。その結果、Chromeは公開からわずか数年で急成長を遂げました。Firefoxも2008～2009年にかけてシェアを伸ばし&lt;strong&gt;2009年11月には32.2%のシェア&lt;/strong&gt;に達して一時的にピークを迎えました。しかしChromeは2009年時点で数％だったシェアを着実に奪取し、&lt;strong&gt;2011年11月にはFirefox約25.2%に対しChromeが25.7%と初めてFirefoxを逆転&lt;/strong&gt;しました。この時、依然トップのIEは約40%でしたが（残りはSafariなど）、ブラウザ市場の勢力図は大きく書き換わりつつありました。&lt;/p&gt;&#10;&lt;p&gt;Firefox陣営も手をこまねいていたわけではありません。2009年には高速化したFirefox 3.5をリリースし、一時は単一バージョンでIE7を超えるなど健闘しました。2011年には長らく開発が難航していたFirefox 4.0を公開し、UI刷新やHTML5対応強化、JavaScript高速化（JägerMonkeyエンジン導入）などテコ入れを図ります。またリリース後は従来の年1回程度の大規模アップデートから、Chromeに倣った&lt;strong&gt;高速リリースサイクル（約6週ごとに新版）&lt;/strong&gt; へと方針転換しました。これは技術革新のスピードについていくための戦略でしたが、頻繁なバージョン更新に戸惑うユーザーもいました。&lt;/p&gt;&#10;&lt;p&gt;他方で、&lt;strong&gt;ウェブ利用のモバイルシフト&lt;/strong&gt;という潮流もFirefoxには逆風となりました。2007年登場のiPhoneや、2008年以降普及したAndroidスマートフォンによりモバイル向けブラウザ利用が拡大します。AppleのSafariはiPhoneの標準ブラウザとしてシェアを伸ばし、Androidでも当初は標準ブラウザ（後にChrome for Android）が大量のユーザーを獲得しました。しかしFirefoxはモバイル分野で出遅れました。Mozillaはモバイル版「Firefox Mobile（開発名Fennec）」を2009年末に一部端末向けに投入、2011年にはAndroid版もリリースしましたが、動作の重さや端末メーカーとの提携不足もあり普及しませんでした。またAppleのポリシー上、iOS向けFirefoxはSafariエンジン（WebKit）のラッピングに留まり差別化が困難でした。スマホ黎明期にモバイル市場で存在感を示せなかったことは、後々までFirefoxの総合シェアに響くことになります。&lt;/p&gt;&#10;&lt;h2 id="20122016年モバイル時代の苦戦と組織的試練"&gt;2012〜2016年：モバイル時代の苦戦と組織的試練&#10;&lt;/h2&gt;&lt;p&gt;2010年代中盤までに、世界のブラウザ利用はPCからモバイルへ大きく移行しました。StatCounterの統計では2016年にモバイルのウェブ利用がPCを逆転しています。この流れの中で、モバイルで弱いFirefoxの相対シェアは低下を避けられませんでした。実際、ある統計では&lt;strong&gt;2016年にFirefoxのデスクトップシェアが7.7%まで落ち込み&lt;/strong&gt;、2000年代半ば以来の低水準となりました。Chromeは同時期に60％前後まで達し、圧倒的首位を占めています。一方、Microsoftは2015年にWindows 10とともに従来のIEに代わる新ブラウザ&lt;strong&gt;Edge&lt;/strong&gt;（EdgeHTMLエンジン）を投入しましたが、そのシェアは伸び悩み、デスクトップ市場でFirefoxと下位を競る状況でした（どちらも一桁台から10％程度のレンジ）。&lt;/p&gt;&#10;&lt;p&gt;Firefoxは苦境打開のため技術面でも組織面でも様々な手を打ちました。技術的課題の一つは&lt;strong&gt;マルチプロセス対応&lt;/strong&gt;の遅れでした。Chromeがタブごとに独立プロセスを割り当てる設計で安定性を高めていたのに対し、Firefoxは長らくプロセス分離を行わず、アドオンとの互換性を重視して単一プロセスで動作していました。その結果、タブが増えると応答が阻害されるなどパフォーマンス面で不利でした。Mozillaは「Electrolysis（e10s）」計画のもとプロセス分離に取り組み、2016年頃から段階的にFirefoxへ導入しました。これによりレンダリングエンジン「Gecko」のプロセスとUIプロセスが分離され、後にコンテンツタブのプロセス並列化も進められました。加えてJavaScriptエンジンを強化したり（2013年IonMonkey導入）、メモリ効率の改善なども行いましたが、依然として「Firefoxは重い」とのイメージが付きまとい、Chromeから流出したユーザーを呼び戻すには至りませんでした。&lt;/p&gt;&#10;&lt;p&gt;拡張機能エコシステムにも転機が訪れました。Firefoxの強みであった強力な拡張機能は、その高度な自由度ゆえにブラウザ本体の構造刷新を難しくしていました。Mozillaは2015年、従来のXUL/XPCOMベースの拡張を廃止し、Chromeに近いAPIを持つ新拡張方式「WebExtensions」への移行を発表します。これはセキュリティ向上や将来の機能追加には有効でしたが、一部の古参ユーザーからは「お気に入りのアドオンが使えなくなる」と反発を招きました。&lt;/p&gt;&#10;&lt;p&gt;この時期、Mozillaの収益面・戦略面でも動きがありました。2014年、Mozillaは米国版Firefoxのデフォルト検索エンジンを、長年提携してきたGoogleからYahoo!に切り替える決断をします。当時MozillaはGoogle Chromeという強力な競合の出現に直面しつつ、収入源の大半をGoogleに依存する状況をリスクと捉えたとも見られます。しかしYahoo!検索への変更はユーザーに歓迎されず、「検索品質より政治的判断を優先した」との批判も受けました。実際、多くのユーザーは手動でGoogle検索に戻したとも言われ、Firefoxの利用継続にマイナスに働いた可能性があります。このYahoo!との契約は5年予定でしたが、2017年にMozillaは契約上の権利を行使して&lt;strong&gt;打ち切り&lt;/strong&gt;、Googleを再びデフォルト検索に戻しました。後に明らかになったところでは、Yahoo!買収に伴う契約条項によりMozillaは年間3億7500万ドルの支払いを受けつつ契約終了を選べる立場にあり、それを行使したようです。いずれにせよ、収入源の再びのGoogle回帰はMozillaの経営のグラつきを示唆しました。Mozillaは他地域でも、中国ではBaidu、ロシアではYandexなど地域ごとの検索提携を行って収益源を多様化させてはいましたが、&lt;strong&gt;Firefoxの収益の約90%が検索連動広告料に依存&lt;/strong&gt;する構造自体は変わっていませんでした。&lt;/p&gt;&#10;&lt;p&gt;2014年には経営トップの交代劇も話題となりました。Mozilla CTOでFirefox開発に携わったブレンダン・アイク氏が一時CEOに就任しましたが、同氏の過去の政治献金がきっかけで内部外部から反発が起こり、就任からわずか11日で辞任する事態となりました。この騒動はMozillaのブランドイメージにも少なからず影響を与え、「自由で開かれたウェブ」を掲げる組織の理念と経営の難しさを露呈しました。ただしブラウザ市場シェアへの直接の影響は限定的であり、Firefox低迷の主因はあくまで製品競争力と市場環境の変化にありました。&lt;/p&gt;&#10;&lt;h2 id="20172019年firefox-quantumによる再起とプライバシー路線"&gt;2017〜2019年：Firefox Quantumによる再起とプライバシー路線&#10;&lt;/h2&gt;&lt;p&gt;2017年、Firefoxは大規模な刷新を伴うリリース「&lt;strong&gt;Firefox 57 (Quantum)&lt;/strong&gt;」を発表します。これはMozillaが数年をかけ進めてきた「Project Quantum」の成果を結集したもので、レンダリングエンジンの中核にRust言語で実装した新技術を導入し、並列処理による高速化を実現しました。例えばCSSのレイアウト計算にはServoプロジェクト由来の「Stylo」エンジンを採用し、マルチコアCPUをフル活用することでスタイル適用を高速化しました。また先述のマルチプロセス対応も完全に有効化され、さらにUIも「Photon」と呼ばれるモダンなデザインに刷新されています。これらによりMozillaは「従来比2倍の高速化、メモリ使用量30%減（対Chrome比）」といった飛躍的性能向上を謳い、かつての機敏さを取り戻すことを目指しました。&lt;/p&gt;&#10;&lt;p&gt;Firefox Quantumはユーザーやメディアから概ね好意的に受け止められました。実際にページ表示の体感速度が向上し、特に大量のタブを開いた際の動作がChromeより軽快との評価も得ました。米Wired誌は「2017年にふさわしいブラウザ」「見えないトラッカーを自動でブロックし、プライバシー重視で履歴も守ってくれる。Chromeより速く、賢い」とQuantumを賞賛しています。加えてPocketの統合（あとで読む機能）やスクリーンショット機能の強化など細かな使い勝手でも改善が見られました。一方で、このタイミングで旧式のアドオンは完全にサポート終了となり、愛用していた一部機能が使えなくなったユーザーもいましたが、全体としてFirefoxのユーザー体験は近代化されました。&lt;/p&gt;&#10;&lt;p&gt;MozillaはFirefox Quantumリリースに合わせてマーケティングとブランドイメージの立て直しも図りました。スローガンに「Firefoxはあなたのためのブラウザ（Firefox fights for you）」と掲げ、&lt;strong&gt;プライバシー重視&lt;/strong&gt;や&lt;strong&gt;非営利&lt;/strong&gt;である点を強調する戦略を明確にします。実際、2015年頃からMozillaは追跡ブロック機能（トラッキング保護）をプライベートブラウジングモードに搭載していましたが、2018～2019年にはこれを強化し、&lt;strong&gt;Enhanced Tracking Protection (ETP)&lt;/strong&gt; として通常ブラウジングでもデフォルト有効化しました。またFacebookなど特定ドメインのトラッカーを分離する「コンテナ」機能も提供し、ユーザーのデータが巨大全に握られないよう工夫しました。こうしたプライバシー機能は競合ブラウザにはないFirefoxの差別化要因となり、特にテクノロジーに詳しい層やプライバシー意識の高いユーザーから支持を集めました。&lt;/p&gt;&#10;&lt;p&gt;Quantum効果もあってか、&lt;strong&gt;2017年末には一時的にFirefoxシェアが持ち直した&lt;/strong&gt;とのデータもあります。NetApplicationsの統計では、2016年に7.7%まで落ち込んだFirefoxのデスクトップシェアが2017年10月には13%近くまで回復しました。しかしこれは長続きしませんでした。Chromeユーザーの大多数はエコシステム（Googleアカウント連携やChrome拡張の蓄積など）にロックインされており、わざわざFirefoxへ乗り換える動機は限定的でした。またWindowsやAndroidといったプラットフォームでのデフォルト地位を持たないFirefoxは、ユーザー獲得でどうしても不利です。結局、&lt;strong&gt;2018年以降Firefoxのシェアは再び緩やかな低下傾向に戻り&lt;/strong&gt;、2019年末時点ではデスクトップで8％前後まで下降しました。&lt;/p&gt;&#10;&lt;p&gt;とはいえMozillaはこの頃から明確に「プライバシー重視」の路線を打ち出したことで、Firefoxのブランドイメージはかつての「速い新興ブラウザ」から「ユーザーの権利を守る良心的なブラウザ」へと変化していきました。実際のユーザー層も少しずつ変化しています。ある統計によれば2023年時点でFirefoxユーザーの約&lt;strong&gt;59%が男性、41%が女性&lt;/strong&gt;で、年齢層では&lt;strong&gt;25～34歳が24.8%と最多&lt;/strong&gt;を占めます。比較的若い技術志向のユーザーに支持されており、その多くはFirefoxの&lt;strong&gt;オープンソース性&lt;/strong&gt;や&lt;strong&gt;高い拡張性&lt;/strong&gt;、そして何より&lt;strong&gt;プライバシー保護へのこだわり&lt;/strong&gt;に価値を見出しています。Firefoxはこうしたコアユーザーを支えに、市場全体では小さいながらも確固とした存在意義を維持する道を模索することになります。&lt;/p&gt;&#10;&lt;h2 id="2020年代市場再編と現在のfirefox"&gt;2020年代：市場再編と現在のFirefox&#10;&lt;/h2&gt;&lt;p&gt;2020年代に入ると、ブラウザ市場はさらに統合が進みました。2019年末、Microsoftは従来のEdgeHTMLエンジンを放棄し、GoogleのChromiumプロジェクトをベースとした新Edge（Blinkエンジン）への移行を発表します。&lt;strong&gt;2020年にはEdgeのChromium版が正式リリース&lt;/strong&gt;され、これにより主要ブラウザのレンダリングエンジンは実質Google系（Blink/Chromium）とApple系（WebKit）の2系統のみとなりました。Mozilla Firefoxの&lt;strong&gt;Geckoエンジンは「Big Tech」に属さない唯一の独立系エンジン&lt;/strong&gt;として残りました。MozillaはかつてIE独占に対抗するためGeckoを開発した経緯があり、ウェブ標準の多様性を守る観点からもFirefox/Geckoの存続意義は大きいとされています。しかし現実のシェアに目を向けると、Firefoxの戦いは厳しさを増しています。&lt;/p&gt;&#10;&lt;p&gt;まず&lt;strong&gt;デスクトップ市場&lt;/strong&gt;では、Windows 10/11にプリインストールされ既定ブラウザとなる新Edgeが一定のシェアを獲得し、2021年にはFirefoxを追い抜きました。StatCounterの統計によれば、2021年3月時点のデスクトップシェアはChrome約67%、Safari約10%、Edge約8.0%、Firefox約7.97%となっており、Firefoxは長年守ってきた「3位」の座をEdgeに明け渡しました。さらに&lt;strong&gt;モバイル市場&lt;/strong&gt;では、Android標準のChromeとiOS標準のSafariが支配的で、Firefoxの存在感はごくわずかです。2024年時点でFirefoxのモバイルシェアはわずか0.6%程度に過ぎないとの分析もあり、総合的に見てもFirefoxのシェアは数％台と推定されています。実際StatCounterによれば2025年2月時点でFirefoxはPC・モバイル含む全世界ブラウザシェアの約&lt;strong&gt;3％前後&lt;/strong&gt;しかなく、デスクトップのみでも&lt;strong&gt;6.36%（第4位）&lt;/strong&gt; に留まっています。一方Chromeは総合で約65%と圧倒的首位、SafariはiPhone効果で20%前後（総合2位）、Edgeや他のChromium派生ブラウザ（Opera、Braveなど）も少なからぬユーザーを擁します。&lt;/p&gt;&#10;&lt;p&gt;このように数字の上ではFirefoxの存在感は小さくなりましたが、Mozillaは製品の差別化と組織の存続に向けて手を打っています。製品面では引き続き&lt;strong&gt;プライバシー保護機能の強化&lt;/strong&gt;が図られました。例えば2021年にはCookieをサイトごとに分離してサードパーティによる追跡を根本的に防ぐ「&lt;strong&gt;総合的なCookie保護（Total Cookie Protection）&lt;/strong&gt;」を実装し、2022年以降これをデフォルト有効にしました。さらに暗号化通信の強制（HTTPS-Onlyモード）や、DNSクエリを暗号化するDNS over HTTPSの標準化など、ユーザーの痕跡が漏れにくい仕組みを積極的に取り入れています。こうした機能強化により、Firefoxは「プライバシーを最優先するユーザーにとっての主要な選択肢」というブランドイメージを確立しました。実際、「Firefoxユーザーの75%はプライバシー機能がFirefoxを使い続ける重要な理由」との調査もあります。また拡張機能の活用も依然盛んで、&lt;strong&gt;ユーザーの70%以上が何らかの拡張機能を導入&lt;/strong&gt;しており、他ブラウザにはない高度なカスタマイズ性も保持しています。&lt;/p&gt;&#10;&lt;p&gt;一方、Mozillaの&lt;strong&gt;収益構造&lt;/strong&gt;は相変わらず脆弱です。Firefoxの市場シェア低下により検索連動収入も縮小傾向にありますが、それでもMozilla全体の収入の大半はFirefox経由の検索エンジン提携によるものです。2022年時点でMozillaの年間収入は約5億ドル、そのうち&lt;strong&gt;90%近くが検索エンジンからのロイヤルティ&lt;/strong&gt;であり、中でもGoogleからの支払いが約4億ドルと最大を占めています。つまり現在でも&lt;strong&gt;Mozilla収入の約8割強はGoogle頼み&lt;/strong&gt;という状況です。このジレンマは2023年に表面化しました。米司法省によるGoogleの反トラスト訴訟に関連して、MozillaのCFOは「もし裁判所がGoogleによるデフォルト検索エンジン契約を禁じれば、Mozillaは事業継続が危うくなる」と証言しました。「収入源を一度に失えば大規模な人員削減が避けられず、開発縮小で製品力が低下しユーザー離れが加速する悪循環に陥りかねない。それはFirefoxをビジネスから退出させる可能性がある」と警鐘を鳴らしています。事実、Mozillaは2020年に250名（全従業員の約1/4）をレイオフしており、経営環境の厳しさがうかがえます。&lt;/p&gt;&#10;&lt;p&gt;もっとも、Mozilla幹部はFirefoxが消滅することの影響についても強調しています。前述の証言でCFOは「Geckoエンジンは&lt;strong&gt;大手テック企業に属さない唯一のブラウザエンジン&lt;/strong&gt;であり、Firefoxが消えればウェブは単一企業群により支配される恐れがある」と述べています。この指摘の通り、2025年現在エンジンレベルではChromium（Google主導）とWebKit（Apple主導）に二極化しており、Firefox/Geckoは多様性維持の要となっています。実際、欧米の技術コミュニティや競争当局からも「ブラウザ市場の単一化（モノカルチャー）への懸念」が表明されており、Firefoxにはシェア以上の存在意義が認められていると言えるでしょう。&lt;/p&gt;&#10;&lt;h2 id="おわりにfirefoxの果たす役割と展望"&gt;おわりに：Firefoxの果たす役割と展望&#10;&lt;/h2&gt;&lt;p&gt;以上、Firefoxの誕生から現在までの盛衰を振り返りました。2000年代、Firefoxは停滞するIEに風穴を開けウェブ標準とユーザー本位の機能を普及させる原動力となりました。2009年前後には世界シェアの3分の1を得て栄華を極めますが、その後はGoogle Chromeという新たな競合の前にシェアを奪われ続けました。2020年代の今日、Firefoxのシェアはわずか数％とかつての勢いは見る影もありません。しかしその存在は決して無意味ではありません。むしろ、商業的動機から距離を置き&lt;strong&gt;ユーザーのプライバシーとオープンなウェブを守る&lt;/strong&gt;というFirefoxの理念は、個人情報保護や独占阻止が重要課題となった現代において一層重要になっています。&lt;/p&gt;&#10;&lt;p&gt;Firefoxのユーザー層は少数ながら根強い支持を示しており、「速度や便利さより信念を重視する」いわばコアな愛好者によって支えられています。Mozillaもまた、Firefox以外の新規事業（VPNサービスやプライバシー重視のPocket提案記事など）を模索しつつ、ブラウザ本体の改良を続けています。今後の課題は、いかにして一般ユーザーにも魅力を感じてもらいシェア低下に歯止めをかけるかです。既定ブラウザの壁は厚いものの、近年ではプライバシー志向の高まりや規制当局の動きも追い風になり得ます。Firefox自身も速度・機能で競合に劣らない水準を維持しており、実用上のハンデは過去ほど大きくありません。あとは「なぜFirefoxなのか」をユーザーに訴求し続けることが重要でしょう。&lt;/p&gt;&#10;&lt;p&gt;結局のところ、Firefoxの盛衰はウェブブラウザ市場のダイナミズムそのものです。かつて独占状態だったIEを打ち破った革新者が、今度は自らより強力な競合に追われる立場となり、それでも理念を掲げて踏みとどまっている――その歴史はウェブの進化と表裏一体です。Firefoxが今後も存続し競争を続けることは、ユーザーに選択肢を提供し続ける上で不可欠であり、ひいてはオープンで健全なインターネットの維持につながると言えるでしょう。その意味で、たとえシェアは小さくともFirefoxの存在価値は今なお失われていないのです。&lt;/p&gt;&#10;</description></item><item><title>2005年〜2025年 Webブラウザ市場シェアの推移</title><link>https://ai.hack-le.com/2005%E5%B9%B4%E3%80%9C2025%E5%B9%B4-web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E5%B8%82%E5%A0%B4%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%AE%E6%8E%A8%E7%A7%BB/</link><pubDate>Sun, 11 May 2025 23:15:08 +0900</pubDate><guid>https://ai.hack-le.com/2005%E5%B9%B4%E3%80%9C2025%E5%B9%B4-web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E5%B8%82%E5%A0%B4%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%AE%E6%8E%A8%E7%A7%BB/</guid><description>&lt;p&gt;過去20年間でWebブラウザの勢力図は劇的に変化しました。2000年代半ばにはMicrosoftのInternet Explorer（IE）が世界市場をほぼ独占していましたが、その後Mozilla FirefoxやGoogle Chromeなどの新興ブラウザが台頭し、現在ではChromeが支配的な地位を占めています。本稿では2005年から2025年までのブラウザ市場シェアの推移を時系列で振り返り、主要ブラウザ（IE、Firefox、Chrome、Safari、Edge、Operaなど）のシェア変動と、その背景にある技術革新、OS戦略、セキュリティ・パフォーマンス要因、さらにはスマートフォンなどデバイス普及の影響について分析します。&lt;/p&gt;&#10;&lt;h2 id="20052009年-ie独占時代とfirefoxの挑戦"&gt;2005〜2009年: IE独占時代とFirefoxの挑戦&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;IE圧倒的シェアとFirefox登場:&lt;/strong&gt; 2005年前後のブラウザ市場はIEが圧倒的支配者で、世界シェアは85〜90%に達していました。IE6（2001年リリース）以降長らく大規模アップデートが途絶えたこともあり、IEはセキュリティ問題や標準非準拠の欠点を抱えていました。この隙を突いてMozilla財団のFirefox（2004年正式版リリース）が急速に支持を集め、2005年末にはFirefoxがシェア約10%超を獲得しています。Firefoxはタブブラウジングや拡張機能、優れた標準準拠性など当時革新的な機能を備え、IEからの乗り換えを促しました。実際、IE7が2006年にタブ機能やフィッシング対策を搭載してリリースされたものの、それらは既にFirefoxやOperaでは一般的だった機能であり、IEは技術革新の面で後手に回っていたことが窺えます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;他ブラウザの状況:&lt;/strong&gt; この時期、Operaも古参ブラウザとして存在感を示していました。Operaはページ表示の高速化や独自の圧縮プロキシ（Opera Mini）など先進的機能で根強いユーザーを持ちましたが、市場シェア自体はデスクトップでは数％以下と限定的でした。AppleのSafariは2003年にMac向けに登場しましたが、当時のMacの普及率が低かったためシェアは僅かでした。ただし2007年に初代iPhoneが発売されるとモバイル版Safariが登場し、少しずつモバイルブラウジング市場での存在感を高め始めます（もっとも2000年代末時点ではスマートフォンからのWeb利用はまだ全体の一部でした）。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;IE独占崩れの兆し:&lt;/strong&gt; こうした新興勢力の台頭により、IEの独占体制に陰りが見え始めます。Firefoxの成功を受けてIEも2006年以降IE7/IE8で機能改善を図りましたが、ユーザーの流出傾向は止まりませんでした。欧州では2009年に欧州委員会の是正措置としてWindows上での「ブラウザ選択画面」の表示（Browser Ballot）が義務付けられ、Windowsユーザーが代替ブラウザを選びやすくなる措置も取られました。このように2000年代後半には &lt;strong&gt;「IE一強」体制が崩れ、Firefoxを筆頭に他ブラウザがシェアを徐々に奪い始める時代&lt;/strong&gt;となったのです。&lt;/p&gt;&#10;&lt;h2 id="20102014年-chromeの台頭とieの没落"&gt;2010〜2014年: Chromeの台頭とIEの没落&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Chromeの登場（2008年）:&lt;/strong&gt; ブラウザ市場に決定的な転機をもたらしたのが、2008年9月にリリースされたGoogle Chromeです。ChromeはSafariと同じWebKitレンダリングエンジンを使いつつ、独自の高速JavaScriptエンジンV8を搭載し圧倒的な動作速度をアピールしました。またタブ毎のプロセス分離による安定性やシンプルなUI、自動アップデートによるセキュリティ向上など技術革新が盛り込まれ、登場直後から注目を集めます。実際Chromeは公開1年後の2009年秋には約3.6%のシェアを獲得し、2010年には早くも二桁％に乗せるなど急速な成長を遂げました。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;IEのシェア急落:&lt;/strong&gt; 一方、IEのシェア低下はこの時期決定的となります。StatCounterの統計では2010年時点でIEはついに世界シェア50%を割り込むまでに低下しました。IEは過去の高シェアゆえにレガシー環境で使われ続けたものの、技術面で先行するChromeやFirefoxとの差が広がり、一般ユーザーの関心も離れていきました。IE9（2011年）やIE10（2012年）でHTML5対応や速度改善も図られましたが焼け石に水で、&lt;strong&gt;2012年5月にはStatCounterの集計でChromeがIEを初めて追い抜き世界トップシェアのブラウザとなりました&lt;/strong&gt;。長年トップだったIEが首位から陥落したことは、ブラウザ戦争における歴史的な節目となりました。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Firefoxの動向とChrome台頭の理由:&lt;/strong&gt; Firefoxは2010年前後にシェア約24%程度でピークに達しましたが、その後は緩やかに下降線をたどります。かつてIE独占に風穴を開けたFirefoxでしたが、Chromeの台頭により徐々にユーザーを奪われた形です。背景にはChromeの持つ高速性能と頻繁な機能アップデート（6週間ごとのリリースサイクル）、そしてGoogleの強力なプロモーション力がありました。Chromeは検索エンジンや各種Webサービスとの連携でユーザー囲い込みを図り、市場シェアを着実に伸ばしました。一方のFirefoxはオープンソースでコミュニティ主導の開発ゆえに商業的パワーに劣り、また一時期動作の重さも指摘されるなど、一般ユーザーへの訴求力でChromeに及ばなくなっていきました。この結果、2010年代前半には&lt;strong&gt;ブラウザ市場は「Chrome一強、IE・Firefox二位争い」という構図&lt;/strong&gt;に移行します。2014年頃にはデスクトップ市場でChromeがシェア50%近くに達し、FirefoxとIEは各20%前後で僅差の2位争いをする状況になっていました。かつて95%を誇ったIEがこの順位まで転落したのは象徴的です。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Safari・Operaの立ち位置:&lt;/strong&gt; Safariはこの時期もデスクトップでは5%前後の小勢力でしたが、Apple製品の人気上昇に伴い緩やかに存在感を増していました。特に2010年にはiPadが発売され、iPhoneと合わせてiOSデバイスからのWebアクセスが拡大します。ただ世界全体で見ると2014年時点でもWeb利用の主流はPCブラウザであり、モバイル（スマホ・タブレット）経由はまだ少数派でした。Operaは2013年に独自エンジンを捨ててChromium（Blinkエンジン）ベースへと転換しましたが、ユーザーベース拡大には繋がらずデスクトップシェアは数％以下のままでした。しかし新興国を中心にOpera Miniが低速回線でも使いやすい圧縮ブラウザとして一定の支持を集め、モバイル分野で独自の役割を果たしました。&lt;/p&gt;&#10;&lt;h2 id="20152019年-モバイル時代の到来とedgeの戦略転換"&gt;2015〜2019年: モバイル時代の到来とEdgeの戦略転換&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;スマートフォン普及による地殻変動:&lt;/strong&gt; 2010年代中盤になると、スマートフォンの爆発的普及がブラウザ市場の勢力図を塗り替え始めます。2016年10月、ついに世界全体のWebアクセスに占めるモバイル（スマホ・タブレット）ブラウザの割合が51.3%となり、デスクトップ（48.7%）を逆転しました。このモバイルシフトにより、AppleのSafari（iPhone/iPad上の標準ブラウザ）とGoogle Chrome（Androidの標準ブラウザとして定着）のシェアが大きく伸長します。実際、モバイル利用の増加に伴ってSafariは世界ブラウザ市場全体で見たシェアを拡大させ、ChromeとSafariの二強体制が強まっていきました。反対に、従来PC上で使われていたIEやFirefoxは相対的に存在感が低下します。特にMicrosoftはスマートフォン分野で存在感を示せず（Windows Phoneのシェアはごく僅か）、モバイルブラウザ市場から取り残されました。このこともIE凋落に拍車をかけた要因です。FirefoxもAndroid版を提供しましたがシェア獲得には至らず、iOS版はエンジン制限（iOSではSafari(WebKit)以外のエンジン利用禁止）のため独自性を出せず、モバイル市場では苦戦しました。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Microsoft Edgeの投入（2015年）:&lt;/strong&gt; 2015年、MicrosoftはWindows 10と共に新ブラウザ「Microsoft Edge」をリリースし、長年のIEからの脱却を図りました。Edgeは新エンジン（EdgeHTML）で高速化・標準準拠を改善し、名称変更でIEの悪いイメージを一新しようという戦略でした。しかしリリース当初のEdgeはWindows 10専用で拡張機能も未成熟だったため、大勢には影響を与えられませんでした。多くのユーザーは引き続きChromeなど他ブラウザを利用し、Edgeのシェアは当初数％に留まりました。とはいえ、Edgeの投入はMicrosoft自体がIEの失敗を認め次世代ブラウザに舵を切ったことを意味し、ブラウザ戦略上の大きな転換点でした。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;市場シェアの集約:&lt;/strong&gt; 2017年前後までに、ブラウザ市場は主要プレーヤーがほぼ出揃い、そのシェアが大きく集約されました。2017年時点で世界シェアを見ると、Chromeが60%以上を占め、Safariがそれに次ぐ存在となる一方で、Firefox・IE・Operaといった他ブラウザはいずれも5%未満に低下しています。同年5月にはMozilla元CTOが「第二次ブラウザ戦争はChromeの勝利に終わった」と宣言するに至りました。事実、2010年代後半にはChrome（およびそのオープンソース版であるChromium）エンジンの事実上の一人勝ちとも言える状況で、Web開発の標準もChrome基準で進むようになります。競合各社もこの流れに対応せざるを得なくなりました。Operaは既にChromiumベースに転換済みでしたが、2018年末には遂にMicrosoftも独自路線を断念し、EdgeをChromium（Blinkエンジン）ベースに作り直す計画を発表します。新生「Chromium版Edge」は2020年初頭に公開され、以降Windows 10/11の標準ブラウザはChromiumエンジンとなりました。このように&lt;strong&gt;ブラウザエンジンの収斂&lt;/strong&gt;も2010年代後半の大きな動きであり、Geckoエンジンを守るFirefox以外はほぼChrome系エンジンに統一される流れとなっています。&lt;/p&gt;&#10;&lt;h2 id="20202025年-現代のブラウザ勢力図"&gt;2020〜2025年: 現代のブラウザ勢力図&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Chrome支配と二番手Safari:&lt;/strong&gt; 2020年代に入ってからもChromeの独走体制は続いており、依然として世界シェアの約2/3をChromeが握っています。ChromeはWindows/MacといったPCだけでなくAndroidスマホでも事実上の標準ブラウザであり、クロスプラットフォームで圧倒的な存在感を示しています。その結果、Web開発者もまずChrome（Blink）で動作確認するのが当たり前になるなど、エコシステムもChrome中心に回っています。Safariは世界シェア約17%で2位グループに位置しています。この数字は主にiPhoneやiPadといったiOSデバイスでの利用によるものです。実際2020年代にはモバイル経由のWebアクセスが全体の60%以上を占めるまでになっており、iOS端末からのアクセスが多い地域ではSafariが非常に高いシェアを持っています。一方でSafariはWindows版提供停止もありMac/iOS以外では使われないため、プラットフォーム依存のシェアと言えます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;EdgeとFirefox、その他の状況:&lt;/strong&gt; Microsoft Edge（Chromium版）は、Windowsへの標準搭載とChromium由来の高い互換性を武器に徐々にユーザー数を増やしつつありますが、そのシェアは2025年時点で約5%前後に留まっています。もっとも、旧IEユーザーの移行先として一定の役割を果たし、2022年6月にはInternet Explorerのサポートがついに正式終了して事実上姿を消しました。Firefoxは2020年代も数％程度のシェアを維持しており、熱心な支持層（プライバシー重視のユーザーや開発者コミュニティ）に支えられて細々と存続しています。しかし大勢に影響を与えるには至らず、市場シェアの面では今も縮小傾向にあります。その他、OperaやSamsung Internet、かつてアジアで人気を博したUC Browserなどもいずれも数％以下のニッチな存在になっています。総じて言えば、&lt;strong&gt;2020年代前半のブラウザ市場は「Chrome帝国」ともいえる支配的状況&lt;/strong&gt;であり、その中でSafariやEdgeが一定の地位を占め、FirefoxやOperaは細々と生き残っている構図です。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;技術・戦略面の総括:&lt;/strong&gt; この20年のシェア変動の背景にはそれぞれ明確な要因がありました。まず&lt;strong&gt;技術革新&lt;/strong&gt;の観点では、レンダリングエンジンやJavaScriptエンジンの性能差、Web標準対応度の違いがユーザー体験を左右し、ブラウザ乗り換えの大きな動機となりました。例えばChromeの高速V8エンジンやマルチプロセス設計は当初画期的で、多くのユーザーが「速いから」という理由でChromeに流れました。また&lt;strong&gt;セキュリティ&lt;/strong&gt;も重要です。IEはActiveXの脆弱性など度重なるセキュリティ問題で信頼を失い、Chromeはサンドボックス機構や自動更新で安全性を売りにしました。&lt;strong&gt;OS戦略&lt;/strong&gt;の面では、MicrosoftがWindowsにIE/Edgeをバンドルしたようにプラットフォームとの結び付きがシェアに直結しましたが、モバイル時代にはGoogleがAndroidにChromeを、AppleがiOSにSafariを組み込むことで覇権を握りました。逆に言えば、モバイルOS市場で敗れたMicrosoftはブラウザ市場でも苦戦を強いられたのです。&lt;strong&gt;ユーザーエクスペリエンスと性能&lt;/strong&gt;もシェアに影響しました。Firefoxの拡張機能エコシステムは熱心なユーザーを引き付けましたが、一般層にはシンプルで高速なChromeが受け入れられました。Operaは独自機能が評価されつつも大衆受けせずニッチに留まりました。&lt;/p&gt;&#10;&lt;p&gt;最後に、&lt;strong&gt;スマートフォン・タブレットの普及&lt;/strong&gt;がブラウザ市場に与えた影響は極めて大きいものがありました。2010年代前半まではPC中心だったインターネット利用が、後半にはモバイル中心へとシフトしたことで、ブラウザ市場の主役もPC向けブラウザからモバイル向けブラウザへと移りました。このモバイルシフトに適応できた企業（GoogleやApple）はシェアを伸ばし、適応が遅れた企業（MozillaやMicrosoft）は相対的に後退する結果となりました。以上のように、2005年から2025年にかけてのブラウザ市場は、技術トレンドとデバイス環境の変化に沿って&lt;strong&gt;IEからFirefoxへ、そしてChromeへの覇権交代&lt;/strong&gt;が進み、現在に至っています。各ブラウザの興亡は、技術革新への対応力とプラットフォーム戦略の巧拙が明暗を分けたと言えるでしょう。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;主な参考資料:&lt;/strong&gt; ブラウザシェア統計（StatCounter等）、ブラウザ戦争の解説、ガーディアン報道（2016年モバイル利用逆転）など。&lt;/p&gt;&#10;</description></item><item><title>Windows バッチスクリプトによる大量の ZIP ファイル作成（7-Zip 利用）</title><link>https://ai.hack-le.com/windows-bat-zip/</link><pubDate>Thu, 13 Mar 2025 14:14:56 +0900</pubDate><guid>https://ai.hack-le.com/windows-bat-zip/</guid><description>&lt;p&gt;本記事では、7-Zip を利用して&lt;strong&gt;複数のフォルダを個別に ZIP 化するバッチスクリプト&lt;/strong&gt;を作成する方法を解説する。本スクリプトは、エクスプローラーで複数のフォルダをドラッグ＆ドロップするだけで、それぞれのフォルダを ZIP ファイルとして圧縮する。大量のフォルダを一括で ZIP 化する作業を効率化できる。&lt;/p&gt;&#10;&lt;h2 id="スクリプトのコード"&gt;スクリプトのコード&#10;&lt;/h2&gt;&lt;p&gt;以下のバッチスクリプトを &lt;code&gt;zip_folders.bat&lt;/code&gt; などの名前で保存し、デスクトップなどに配置することで、エクスプローラーからフォルダをドラッグ＆ドロップするだけで ZIP 化できる。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bat" data-lang="bat"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;echo&lt;/span&gt; off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chcp 65001 &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; nul&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;setlocal&lt;/span&gt; enabledelayedexpansion&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sevenZip=C:\Program Files\7-Zip\7z.exe&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;rem ドラッグ＆ドロップされたすべてのフォルダを処理&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="se"&gt;%%&lt;/span&gt;F &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;%*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;rem フォルダが存在するか確認&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;exist&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;%%&lt;/span&gt;&lt;span class="s2"&gt;~F&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;folderPath=&lt;/span&gt;&lt;span class="se"&gt;%%&lt;/span&gt;&lt;span class="s2"&gt;~dpF&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;folderName=&lt;/span&gt;&lt;span class="se"&gt;%%&lt;/span&gt;&lt;span class="s2"&gt;~nxF&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;rem 各フォルダを個別に ZIP 化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%sevenZip%&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; a -tzip &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;!folderPath!!folderName!&lt;/span&gt;&lt;span class="s2"&gt;.zip&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;%%&lt;/span&gt;&lt;span class="s2"&gt;~F\*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;echo&lt;/span&gt; すべての ZIP 化が完了しました。&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;pause&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="スクリプトの詳細解説"&gt;スクリプトの詳細解説&#10;&lt;/h2&gt;&lt;h3 id="1-echo-off"&gt;1. &lt;code&gt;@echo off&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;バッチスクリプトの実行時にコマンドの入力行を非表示にする。これにより、実行中のコマンドがコンソールに表示されず、出力がすっきりする。&lt;/p&gt;&#10;&lt;h3 id="2-chcp-65001--nul"&gt;2. &lt;code&gt;chcp 65001 &amp;gt; nul&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;バッチスクリプトの文字コードを &lt;strong&gt;UTF-8（コードページ 65001）&lt;/strong&gt; に変更する。これにより、日本語のファイル名やメッセージが文字化けしにくくなる。&lt;br&gt;&#10;&lt;code&gt;&amp;gt; nul&lt;/code&gt; を付けることで、コードページ変更のメッセージを非表示にしている。&lt;/p&gt;&#10;&lt;h3 id="3-setlocal-enabledelayedexpansion"&gt;3. &lt;code&gt;setlocal enabledelayedexpansion&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;遅延環境変数展開を有効にする。&lt;br&gt;&#10;バッチスクリプトでは、通常の &lt;code&gt;set&lt;/code&gt; コマンドによる変数の値は即時展開されるため、&lt;code&gt;for&lt;/code&gt; ループの中で &lt;code&gt;set&lt;/code&gt; した変数を &lt;code&gt;!変数名!&lt;/code&gt; の形式で使うと、リアルタイムで値が展開されるようになる。&lt;br&gt;&#10;これにより、&lt;code&gt;for&lt;/code&gt; ループ内で &lt;code&gt;set&lt;/code&gt; した &lt;code&gt;folderPath&lt;/code&gt; や &lt;code&gt;folderName&lt;/code&gt; を適切に扱えるようになる。&lt;/p&gt;&#10;&lt;h3 id="4-set-sevenzipcprogram-files7-zip7zexe"&gt;4. &lt;code&gt;set &amp;quot;sevenZip=C:\Program Files\7-Zip\7z.exe&amp;quot;&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;7-Zip の実行ファイルのパスを変数 &lt;code&gt;sevenZip&lt;/code&gt; に格納する。&lt;br&gt;&#10;7-Zip をデフォルトの場所にインストールしていない場合は、ここを適切なパスに変更する必要がある。&lt;/p&gt;&#10;&lt;h3 id="5-for-f-in--do-"&gt;5. &lt;code&gt;for %%F in (%*) do (...)&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;バッチファイルにドラッグ＆ドロップされたすべてのフォルダを &lt;code&gt;for&lt;/code&gt; ループで処理する。&lt;br&gt;&#10;&lt;code&gt;%*&lt;/code&gt; はバッチスクリプトに渡されたすべての引数を表し、&lt;code&gt;%%F&lt;/code&gt; にフォルダのパスが順番に渡される。&lt;/p&gt;&#10;&lt;h3 id="6-if-exist-f"&gt;6. &lt;code&gt;if exist &amp;quot;%%~F&amp;quot;&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;フォルダが実際に存在するかを確認する。存在しない場合はスキップする。&lt;/p&gt;&#10;&lt;h3 id="7-set-folderpathdpf"&gt;7. &lt;code&gt;set &amp;quot;folderPath=%%~dpF&amp;quot;&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;%%~dpF&lt;/code&gt; を利用して、ドラッグ＆ドロップされたフォルダの&lt;strong&gt;親ディレクトリのパス&lt;/strong&gt;を取得する。&lt;/p&gt;&#10;&lt;h3 id="8-set-foldernamenxf"&gt;8. &lt;code&gt;set &amp;quot;folderName=%%~nxF&amp;quot;&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;%%~nxF&lt;/code&gt; を利用して、フォルダの&lt;strong&gt;名前のみ&lt;/strong&gt;を取得する。&lt;/p&gt;&#10;&lt;h3 id="9-sevenzip-a--tzip-folderpathfoldernamezip-f"&gt;9. &lt;code&gt;&amp;quot;%sevenZip%&amp;quot; a -tzip &amp;quot;!folderPath!!folderName!.zip&amp;quot; &amp;quot;%%~F\*&amp;quot;&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;7-Zip の &lt;code&gt;a&lt;/code&gt;（追加）コマンドを使用して ZIP ファイルを作成する。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-tzip&lt;/code&gt; : ZIP 形式で圧縮（&lt;code&gt;-t7z&lt;/code&gt; に変更すれば &lt;code&gt;.7z&lt;/code&gt; 形式で圧縮可能）&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;!folderPath!!folderName!.zip&lt;/code&gt; : 出力する ZIP ファイルのフルパス（フォルダと同じディレクトリに作成）&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;&amp;quot;%%~F\*&amp;quot;&lt;/code&gt; : ZIP に含めるファイル（フォルダ内のすべてのファイル）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="10-echo-すべての-zip-化が完了しました"&gt;10. &lt;code&gt;echo すべての ZIP 化が完了しました。&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;処理完了後にメッセージを表示する。&lt;/p&gt;&#10;&lt;h3 id="11-pause"&gt;11. &lt;code&gt;pause&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;pause&lt;/code&gt; を実行することで、スクリプト終了時に「続行するには何かキーを押してください&amp;hellip;」と表示され、ユーザーがキーを押すまでコンソールが閉じない。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="使用方法"&gt;使用方法&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;上記のスクリプトを &lt;code&gt;zip_folders.bat&lt;/code&gt; という名前で保存&lt;/li&gt;&#10;&lt;li&gt;圧縮したいフォルダを複数選択し、バッチファイルにドラッグ＆ドロップ&lt;/li&gt;&#10;&lt;li&gt;各フォルダごとに ZIP ファイルが作成される&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="動作例"&gt;動作例&#10;&lt;/h2&gt;&lt;h3 id="-入力バッチファイルにドラッグドロップするフォルダ"&gt;📂 入力（バッチファイルにドラッグ＆ドロップするフォルダ）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;D:\Projects\FolderA\&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;D:\Projects\FolderB\&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;D:\Projects\FolderC\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-出力zip-ファイル"&gt;🔽 出力（ZIP ファイル）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;D:\Projects\FolderA.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;D:\Projects\FolderB.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;D:\Projects\FolderC.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="カスタマイズ"&gt;カスタマイズ&#10;&lt;/h2&gt;&lt;h3 id="zip-ファイルの保存先を変更"&gt;ZIP ファイルの保存先を変更&#10;&lt;/h3&gt;&lt;p&gt;現在のスクリプトでは ZIP ファイルを&lt;strong&gt;元のフォルダと同じ場所に作成&lt;/strong&gt;するが、特定のフォルダに保存したい場合は、以下のように変更する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bat" data-lang="bat"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;outputPath=D:\Compressed&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%sevenZip%&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; a -tzip &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;!outputPath!&lt;/span&gt;&lt;span class="s2"&gt;\!folderName!.zip&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;%%&lt;/span&gt;&lt;span class="s2"&gt;~F\*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、すべての ZIP ファイルが &lt;code&gt;D:\Compressed&lt;/code&gt; フォルダに保存される。&lt;/p&gt;&#10;&lt;h3 id="7z-形式で圧縮"&gt;7z 形式で圧縮&#10;&lt;/h3&gt;&lt;p&gt;ZIP 形式ではなく &lt;strong&gt;7z 形式&lt;/strong&gt; で圧縮したい場合は、以下のように変更する。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bat" data-lang="bat"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%sevenZip%&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; a -t7z &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;!folderPath!!folderName!&lt;/span&gt;&lt;span class="s2"&gt;.7z&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;%%&lt;/span&gt;&lt;span class="s2"&gt;~F\*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;7-Zip のインストールが必要&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;C:\Program Files\7-Zip\7z.exe&lt;/code&gt; に &lt;code&gt;7z.exe&lt;/code&gt; があることを確認する。&lt;/li&gt;&#10;&lt;li&gt;違う場所にインストールされている場合は、&lt;code&gt;set &amp;quot;sevenZip=...&amp;quot;&lt;/code&gt; を修正する。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;フォルダ名に &lt;code&gt;!&lt;/code&gt; &lt;code&gt;(&lt;/code&gt; &lt;code&gt;)&lt;/code&gt; などの特殊文字があると問題が発生する可能性&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;setlocal enabledelayedexpansion&lt;/code&gt; の影響で &lt;code&gt;!&lt;/code&gt; を含むフォルダ名は正しく処理されない可能性がある。&lt;/li&gt;&#10;&lt;li&gt;必要ならフォルダ名の特殊文字を削除する処理を追加する。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;このバッチスクリプトを使用すると、エクスプローラーで&lt;strong&gt;複数のフォルダをドラッグ＆ドロップするだけで、それぞれのフォルダを個別に ZIP 化できる&lt;/strong&gt;。7-Zip のコマンドラインを活用することで、大量のフォルダを効率的に圧縮可能となる。&lt;/p&gt;&#10;</description></item><item><title>TLB (Translation Lookaside Buffer) とは</title><link>https://ai.hack-le.com/tlb-translation-lookaside-buffer/</link><pubDate>Sun, 19 Jan 2025 18:11:59 +0900</pubDate><guid>https://ai.hack-le.com/tlb-translation-lookaside-buffer/</guid><description>&lt;p&gt;TLB (Translation Lookaside Buffer) は、コンピュータの仮想メモリシステムにおいて、仮想アドレスを物理アドレスに変換する際の速度を向上させるために使用されるキャッシュの一種です。CPU内部に実装され、仮想メモリのページテーブルの一部をキャッシュします。&lt;/p&gt;&#10;&lt;h2 id="なぜtlbが必要なのか"&gt;なぜTLBが必要なのか&#10;&lt;/h2&gt;&lt;h3 id="仮想メモリの基本"&gt;仮想メモリの基本&#10;&lt;/h3&gt;&lt;p&gt;仮想メモリでは、プログラムがアクセスするアドレス（仮想アドレス）は、実際の物理メモリ上のアドレスに変換される必要があります。この変換にはページテーブルが使用されます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ページテーブルはメモリ上に保存されており、アクセスには時間がかかります。&lt;/li&gt;&#10;&lt;li&gt;仮想アドレスから物理アドレスへの変換が頻繁に行われるため、変換処理が遅いとシステム全体のパフォーマンスが低下します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="tlbの役割"&gt;TLBの役割&#10;&lt;/h3&gt;&lt;p&gt;TLBは、ページテーブルの一部をキャッシュすることで、仮想アドレスから物理アドレスへの変換を高速化します。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TLBにキャッシュされたエントリがある場合（TLBヒット）、ページテーブルを参照せずにアドレス変換が可能。&lt;/li&gt;&#10;&lt;li&gt;TLBにキャッシュがない場合（TLBミス）は、通常のページテーブルアクセスが発生します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="なぜメモリは相対的に遅いのか"&gt;なぜメモリは相対的に遅いのか？&#10;&lt;/h3&gt;&lt;p&gt;「メモリアクセスは速い」というイメージがありますが、実際にはCPUが必要とする速度に対してメモリは相対的に遅いです。&lt;strong&gt;TLB&lt;/strong&gt; のようなキャッシュが必要な理由と、メモリアクセスの速度が制限される要因を詳しく説明します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;メモリ速度の物理的制約&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;DRAM（メインメモリ）は、ストレージに比べると高速ですが、CPUの動作速度（GHzオーダー）に比べると遥かに遅い（数十～数百ナノ秒）。&lt;/li&gt;&#10;&lt;li&gt;電子信号が物理的にメモリセルに到達し、データを読み取るのに時間がかかります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;プロセッサとメモリの性能ギャップ&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;CPU性能（クロック周波数）は数十年で急速に向上&lt;/strong&gt;してきましたが、メモリの速度向上はそれに比べると緩やか。&lt;/li&gt;&#10;&lt;li&gt;このギャップが「メモリボトルネック」を生み出します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;&lt;strong&gt;ページテーブル参照のコスト&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;仮想メモリのページテーブルをメモリから直接読み取る場合、通常のメモリアクセスよりもさらに遅くなります。&lt;/li&gt;&#10;&lt;li&gt;ページテーブルの階層構造（1段目、2段目&amp;hellip;）を順にたどる必要があるため、変換に複数回のメモリアクセスが発生します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="tlbがメモリより高速な理由"&gt;TLBがメモリより高速な理由&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;TLBはキャッシュ&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TLBはCPU内部にある専用の小さなメモリ（SRAM）で構成されており、アクセス時間は数クロック程度。&lt;/li&gt;&#10;&lt;li&gt;メインメモリ（DRAM）に比べて桁違いに高速です（数十ナノ秒 vs 数ピコ秒）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;局所性の原理&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;プログラムのメモリアクセスには「&lt;strong&gt;空間的局所性&lt;/strong&gt;」と「&lt;strong&gt;時間的局所性&lt;/strong&gt;」があるため、同じページにアクセスする頻度が高い。&lt;/li&gt;&#10;&lt;li&gt;TLBに保持されている最近使われたページ情報を利用することで、高速な変換が可能。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;&lt;strong&gt;ページテーブルの参照回避&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;通常、ページテーブルの参照には複数のメモリアクセスが必要ですが、TLBヒット時はこれを完全にスキップできます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="具体的な速度比較"&gt;具体的な速度比較&#10;&lt;/h3&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;コンポーネント&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;アクセス時間&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;役割&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;レジスタ（CPU内部）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数ピコ秒 (~1サイクル)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最速のデータ保存領域&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;TLB（CPU内部キャッシュ）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数ピコ秒 (~数サイクル)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;仮想→物理アドレス変換を高速化&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;L1キャッシュ&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数ピコ秒 (~数サイクル)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;データキャッシュ（小容量・高速）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;L2キャッシュ&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数十ピコ秒&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;データキャッシュ（中容量・中速）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;メインメモリ（DRAM）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数十～数百ナノ秒&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;大容量だが遅い&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="例-メモリアクセスでのtlb利用"&gt;例: メモリアクセスでのTLB利用&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;TLBヒットの場合&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;CPUが仮想アドレス &lt;code&gt;0x12345&lt;/code&gt; にアクセス。&lt;/li&gt;&#10;&lt;li&gt;TLBにそのアドレスの変換情報がある場合、即座に物理アドレスを取得。&lt;/li&gt;&#10;&lt;li&gt;アクセスは数ピコ秒で完了。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;TLBミスの場合&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TLBに対応情報がない場合、ページテーブルをメモリから参照。&lt;/li&gt;&#10;&lt;li&gt;複数回のメモリアクセス（階層的なページテーブル参照）により、数十～数百ナノ秒の遅延が発生。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="tlbがなぜ重要か"&gt;TLBがなぜ重要か？&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;高速性&lt;/strong&gt;: CPUは1クロックの遅延も性能に直結します。TLBは、仮想アドレスの変換における遅延を大幅に削減します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;効率性&lt;/strong&gt;: ページテーブルの参照を減らすことで、メモリの帯域を他の処理に利用できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;TLBは、仮想メモリ管理の中で「隠れたエンジン」のような役割を果たしています。直接ユーザーが操作するものではありませんが、システムの高速化には欠かせない要素です。CPUとメモリの速度差を埋めるために、TLBを含む多層キャッシュが用意されています。&lt;/p&gt;&#10;&lt;h2 id="tlbの仕組み"&gt;TLBの仕組み&#10;&lt;/h2&gt;&lt;h3 id="1-基本構造"&gt;1. 基本構造&#10;&lt;/h3&gt;&lt;p&gt;TLBは、次の情報を保持するキャッシュ構造です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;仮想ページ番号&lt;/strong&gt;: 仮想アドレスのページ番号。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;物理ページ番号&lt;/strong&gt;: 対応する物理アドレスのページ番号。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;アクセス権限&lt;/strong&gt;: 読み取り、書き込み、実行の可否。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-動作の流れ"&gt;2. 動作の流れ&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;プロセッサがメモリアクセスを試みると、仮想アドレスのページ番号を元にTLBを検索。&lt;/li&gt;&#10;&lt;li&gt;TLBヒットの場合、対応する物理ページ番号が即座に取得され、メモリアクセスが完了。&lt;/li&gt;&#10;&lt;li&gt;TLBミスの場合、&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ページテーブルを参照し、対応するエントリを取得。&lt;/li&gt;&#10;&lt;li&gt;TLBに新しいエントリをキャッシュ。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="3-階層構造"&gt;3. 階層構造&#10;&lt;/h3&gt;&lt;p&gt;多くのモダンなプロセッサでは、TLBは階層化されています：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;L1 TLB&lt;/strong&gt;: 高速だが小容量（数十エントリ）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;L2 TLB&lt;/strong&gt;: やや遅いが大容量（数百〜数千エントリ）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;その通りです。TLB（Translation Lookaside Buffer）は、ハードウェアレベルで実現されたキャッシュです。その物理的な構造と、どうやって高速な動作を達成しているのかを解説します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="tlbの物理的な実現"&gt;TLBの物理的な実現&#10;&lt;/h2&gt;&lt;p&gt;TLBは、以下の要素を含むハードウェア回路として実装されています。&lt;/p&gt;&#10;&lt;h3 id="1-sramベースのキャッシュ"&gt;1. SRAMベースのキャッシュ&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;TLBは、小容量で高速な&lt;strong&gt;SRAM&lt;/strong&gt;（Static Random Access Memory）を使っています。&lt;/li&gt;&#10;&lt;li&gt;各エントリに仮想アドレスと対応する物理アドレスが格納されています。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-連想メモリcam-content-addressable-memory"&gt;2. 連想メモリ（CAM: Content Addressable Memory）&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;連想メモリ（CAM）は、入力データ（仮想アドレス）に対して同時に複数のエントリを比較し、該当するエントリを高速に見つけ出す専用ハードウェアです。&lt;/li&gt;&#10;&lt;li&gt;この仕組みにより、通常のキャッシュよりも効率的にアドレス変換が行えます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="3-tlbエントリの構成"&gt;3. TLBエントリの構成&#10;&lt;/h3&gt;&lt;p&gt;各エントリには以下の情報が含まれています：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;仮想ページ番号（VPN: Virtual Page Number）&lt;/li&gt;&#10;&lt;li&gt;物理ページ番号（PPN: Physical Page Number）&lt;/li&gt;&#10;&lt;li&gt;権限ビット（例: 読み取り/書き込み可能か）&lt;/li&gt;&#10;&lt;li&gt;有効ビット（Valid bit: エントリが有効かどうか）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="4-マルチレベルのtlb"&gt;4. マルチレベルのTLB&#10;&lt;/h3&gt;&lt;p&gt;現代のプロセッサでは、L1キャッシュやL2キャッシュと同様に、TLBにも階層構造があります：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;L1 TLB&lt;/strong&gt;: 非常に高速で小さなTLB。直近でアクセスしたページ情報を保持。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;L2 TLB&lt;/strong&gt;: L1 TLBミス時にアクセス。少し遅いが、より多くのエントリを保持。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;TLBは、専用のハードウェア（SRAM + CAM）で実現されており、その並列検索機能やパイプライン化により、仮想アドレスから物理アドレスへの変換をほぼ1クロックで完了します。これにより、CPUとメモリの速度ギャップを埋める重要な役割を果たしています。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="ページサイズとの関係"&gt;ページサイズとの関係&#10;&lt;/h2&gt;&lt;h3 id="1-ページサイズがtlbに与える影響"&gt;1. ページサイズがTLBに与える影響&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;小さいページサイズ&lt;/strong&gt;: TLBエントリごとにカバーするメモリアドレス範囲が狭くなり、TLBエントリ数が増加。&#10;&lt;ul&gt;&#10;&lt;li&gt;メリット: メモリの細かい管理が可能。&lt;/li&gt;&#10;&lt;li&gt;デメリット: TLBミスが増え、性能低下の可能性。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;大きいページサイズ&lt;/strong&gt;: TLBエントリごとにカバーするメモリアドレス範囲が広がり、エントリ数が少なくても多くのアドレスをカバー可能。&#10;&lt;ul&gt;&#10;&lt;li&gt;メリット: TLBミスが減少し、性能向上。&lt;/li&gt;&#10;&lt;li&gt;デメリット: 内部断片化が発生し、メモリ効率が低下。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-大ページ-huge-pages"&gt;2. 大ページ (Huge Pages)&#10;&lt;/h3&gt;&lt;p&gt;大規模なアプリケーションでは、大ページサイズ（例: 2MBや1GB）を使用することで、TLBミスを最小限に抑える設計が一般的です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: データベースやハイパフォーマンスコンピューティング（HPC）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="実際の使用例と設計"&gt;実際の使用例と設計&#10;&lt;/h2&gt;&lt;h3 id="1-データベースシステム"&gt;1. データベースシステム&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;大量のメモリを効率的に扱うため、大ページを使用してTLBミスを削減。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-組み込みシステム"&gt;2. 組み込みシステム&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;メモリリソースが限られているため、小ページを使用して細かく管理。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="3-ゲームエンジンやリアルタイム処理"&gt;3. ゲームエンジンやリアルタイム処理&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;L1 TLBに収まる範囲でメモリアクセスを最適化。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;TLBは、仮想メモリシステムにおける高速アドレス変換を可能にする重要なコンポーネントです。ページサイズとの相互関係を理解することで、システム性能の最適化や効率的なメモリ利用が可能になります。&lt;/p&gt;&#10;&lt;p&gt;特に、組み込みシステムや高性能アプリケーションでは、TLBとページサイズのバランスを考慮した設計が重要です。&lt;/p&gt;&#10;</description></item><item><title>コンピュータ基礎：ページサイズ (Page Size) とは</title><link>https://ai.hack-le.com/computer-pagesize/</link><pubDate>Sun, 19 Jan 2025 17:47:28 +0900</pubDate><guid>https://ai.hack-le.com/computer-pagesize/</guid><description>&lt;p&gt;ページサイズは、コンピュータシステムがメモリを管理する際の基本単位です。この概念は、仮想メモリと物理メモリの対応付けや効率的なメモリ管理において重要な役割を果たします。&lt;/p&gt;&#10;&lt;h2 id="ページサイズの概要"&gt;ページサイズの概要&#10;&lt;/h2&gt;&lt;h3 id="1-仮想メモリと物理メモリ"&gt;1. 仮想メモリと物理メモリ&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;仮想メモリ&lt;/strong&gt;: プログラムが利用する抽象化されたアドレス空間。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;物理メモリ&lt;/strong&gt;: 実際のRAMやストレージ。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;仮想メモリと物理メモリを効率的に対応付けるため、メモリ空間は固定サイズの&lt;strong&gt;ページ&lt;/strong&gt;に分割されます。各ページには、仮想メモリ上のページ番号と物理メモリ上のフレーム番号が関連付けられます。&lt;/p&gt;&#10;&lt;h3 id="2-固定サイズの理由"&gt;2. 固定サイズの理由&#10;&lt;/h3&gt;&lt;p&gt;ページのサイズが固定であることで、以下の利点があります：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;メモリ管理の簡略化（割り当て、解放、再利用が容易）。&lt;/li&gt;&#10;&lt;li&gt;ページテーブル構造が単純化される。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="一般的なページサイズ"&gt;一般的なページサイズ&#10;&lt;/h2&gt;&lt;h3 id="1-典型的なサイズ"&gt;1. 典型的なサイズ&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;通常のシステム: &lt;strong&gt;4KB (4096バイト)&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;高性能システム: &lt;strong&gt;2MB&lt;/strong&gt; または &lt;strong&gt;1GB&lt;/strong&gt; の大ページ (Huge Pages) をサポート。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-例-システムごとのページサイズ"&gt;2. 例: システムごとのページサイズ&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Linux (一般的な環境)&lt;/strong&gt; : 4KB&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;RedPitaya&lt;/strong&gt;: 4KB&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;macOS (M1/M2)&lt;/strong&gt; : 16KB&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;これらの違いは、システム設計やアプリケーション要件に基づいています。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="ページサイズの役割"&gt;ページサイズの役割&#10;&lt;/h2&gt;&lt;h3 id="1-メモリ管理の効率化"&gt;1. メモリ管理の効率化&#10;&lt;/h3&gt;&lt;p&gt;仮想アドレス空間をページ単位で区切り、必要なページだけを物理メモリに割り当てます。不要なページはディスクにスワップされることもあります。&lt;/p&gt;&#10;&lt;h3 id="2-メモリ保護"&gt;2. メモリ保護&#10;&lt;/h3&gt;&lt;p&gt;各ページにアクセス権限を設定することで、異常なメモリアクセスやセキュリティリスクを防ぎます。&lt;/p&gt;&#10;&lt;h3 id="3-キャッシュ効率"&gt;3. キャッシュ効率&#10;&lt;/h3&gt;&lt;p&gt;CPUキャッシュやTLB (Translation Lookaside Buffer) において、ページサイズがキャッシュ効率に影響を与えます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="ページサイズの影響"&gt;ページサイズの影響&#10;&lt;/h2&gt;&lt;h3 id="1-ページサイズが小さい場合"&gt;1. ページサイズが小さい場合&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;メリット: メモリの細かい管理が可能。&lt;/li&gt;&#10;&lt;li&gt;デメリット: ページ数が増加し、ページテーブルが大きくなる。TLBミスが多発する可能性。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-ページサイズが大きい場合"&gt;2. ページサイズが大きい場合&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;メリット: ページテーブルのエントリが減少し、管理コストが低下。&lt;/li&gt;&#10;&lt;li&gt;デメリット: 小さなデータで余剰メモリが発生する（内部断片化）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="linuxでの確認方法"&gt;Linuxでの確認方法&#10;&lt;/h2&gt;&lt;h3 id="1-ページサイズを確認"&gt;1. ページサイズを確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getconf PAGESIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;例: &lt;code&gt;4096&lt;/code&gt;（4KB）&lt;/p&gt;&#10;&lt;h3 id="2-大ページの確認"&gt;2. 大ページの確認&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/meminfo | grep HugePages&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;大ページの設定状況を確認できます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="ページサイズの設定が必要なケース"&gt;ページサイズの設定が必要なケース&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;組み込みシステム&lt;/strong&gt;: メモリリソースが限られている場合。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;データベースシステム&lt;/strong&gt;: 大きなデータブロックを扱う際に、TLB効率を考慮してページサイズを変更。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ハイパフォーマンスコンピューティング&lt;/strong&gt;: 高速なデータ転送やキャッシュ効率を重視。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;ページサイズは、メモリ管理の基本単位として、システム設計やパフォーマンスに大きな影響を与える重要な要素です。システムに応じたページサイズの理解と設定は、効率的なメモリ利用や性能最適化に役立ちます。&lt;/p&gt;&#10;&lt;p&gt;特に、組み込みシステムや特殊なアプリケーションでは、ページサイズの知識が直接的に開発効率や製品品質に結びつきます。&lt;/p&gt;&#10;</description></item><item><title>AWS DynamoDBでQuery操作を行う方法【Boto3】</title><link>https://ai.hack-le.com/dynamodb-query/</link><pubDate>Wed, 08 Jan 2025 10:41:44 +0900</pubDate><guid>https://ai.hack-le.com/dynamodb-query/</guid><description>&lt;p&gt;DynamoDBの&lt;code&gt;Query&lt;/code&gt;操作は、テーブルまたはインデックスのパーティションキーを指定し、条件に一致するデータを取得するために使用します。この備忘録では、基本的な使い方から応用例までを紹介します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="必要なモジュールのインポート"&gt;必要なモジュールのインポート&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;boto3&lt;/code&gt;&lt;/strong&gt; : AWS SDK for Python。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;boto3.dynamodb.conditions.Key&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;KeyConditionExpression&lt;/code&gt; に使用。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;boto3.dynamodb.conditions.Attr&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;FilterExpression&lt;/code&gt; に使用。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="dynamodbリソースの初期化"&gt;DynamoDBリソースの初期化&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBテーブルを操作するには、Boto3リソースまたはクライアントを使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# DynamoDBリソースの初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dynamodb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# テーブルを指定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YourTableName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="基本的なquery操作"&gt;基本的なQuery操作&#10;&lt;/h2&gt;&lt;h4 id="パーティションキーのみを指定"&gt;パーティションキーのみを指定&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果を表示&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="パーティションキー--ソートキー条件"&gt;パーティションキー + ソートキー条件&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sort_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# ソートキーの条件を追加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果を表示&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="結果のソート順を変更"&gt;結果のソート順を変更&#10;&lt;/h2&gt;&lt;h4 id="昇順デフォルト"&gt;昇順（デフォルト）&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ScanIndexForward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# 昇順&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="降順"&gt;降順&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ScanIndexForward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="c1"&gt;# 降順&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="フィルタリングを追加"&gt;フィルタリングを追加&#10;&lt;/h2&gt;&lt;h4 id="filterexpression-を使用"&gt;&lt;code&gt;FilterExpression&lt;/code&gt; を使用&#10;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;FilterExpression&lt;/code&gt; を使用すると、データの一部を除外できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FilterExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;attribute_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;example_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 属性のフィルタリング&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: &lt;code&gt;FilterExpression&lt;/code&gt; はDynamoDBから取得したデータのフィルタリングを行います。&lt;code&gt;KeyConditionExpression&lt;/code&gt; とは異なり、データスキャン後にフィルタリングされるためコストが増加する可能性があります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="結果のページング処理"&gt;結果のページング処理&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBはデフォルトで1MBのデータを返します。結果が複数ページにわたる場合、&lt;code&gt;LastEvaluatedKey&lt;/code&gt; を使用して次のページを取得します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ページング処理&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LastEvaluatedKey&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ExclusiveStartKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LastEvaluatedKey&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 次のページの開始キー&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 全データを表示&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="インデックスを使用したquery"&gt;インデックスを使用したQuery&#10;&lt;/h2&gt;&lt;p&gt;ローカルセカンダリインデックス（LSI）やグローバルセカンダリインデックス（GSI）を指定してクエリを実行できます。&lt;/p&gt;&#10;&lt;h4 id="例-gsiの指定"&gt;例: GSIの指定&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;IndexName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YourGSIName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# インデックス名を指定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gsi_partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="エラーハンドリング"&gt;エラーハンドリング&#10;&lt;/h2&gt;&lt;p&gt;DynamoDB操作中にエラーが発生する場合に備えて、エラーハンドリングを追加します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;エラーが発生しました: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="実際のデータ例"&gt;実際のデータ例&#10;&lt;/h2&gt;&lt;h4 id="テーブル構造"&gt;テーブル構造&#10;&lt;/h4&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Partition Key&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Sort Key&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Data&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;user1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2023-01-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry A&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;user1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2023-01-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry B&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;user2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2023-01-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry C&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h4 id="クエリ結果例"&gt;クエリ結果例&#10;&lt;/h4&gt;&lt;p&gt;クエリ: &lt;code&gt;Key('partition_key').eq('user1') &amp;amp; Key('sort_key').gte('2023-01-01')&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;結果:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { &amp;#34;Partition Key&amp;#34;: &amp;#34;user1&amp;#34;, &amp;#34;Sort Key&amp;#34;: &amp;#34;2023-01-01&amp;#34;, &amp;#34;Data&amp;#34;: &amp;#34;Entry A&amp;#34; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { &amp;#34;Partition Key&amp;#34;: &amp;#34;user1&amp;#34;, &amp;#34;Sort Key&amp;#34;: &amp;#34;2023-01-02&amp;#34;, &amp;#34;Data&amp;#34;: &amp;#34;Entry B&amp;#34; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="注意点とベストプラクティス"&gt;注意点とベストプラクティス&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;適切なインデックス設計&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;効率的なクエリを実現するため、事前にパーティションキーとソートキーを適切に設計します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;FilterExpression&lt;/code&gt; の使用を最小限に&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;KeyConditionExpression&lt;/code&gt; を活用し、スキャンコストを削減。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;&lt;strong&gt;エラー処理&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ネットワークエラーやスロットリング（リクエスト制限）に備えてリトライロジックを実装。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;これでDynamoDBのQuery操作に関する基本と応用が網羅されています。必要に応じてコピー＆ペーストして活用してください！&lt;/p&gt;&#10;</description></item><item><title>AWKを使った簡単な合計計算の方法</title><link>https://ai.hack-le.com/awk-sum/</link><pubDate>Thu, 19 Dec 2024 11:02:34 +0900</pubDate><guid>https://ai.hack-le.com/awk-sum/</guid><description>&lt;p&gt;AWKはテキスト処理に非常に便利なツールであり、数値の合計を簡単に計算する方法を備えています。本記事では、AWKを使用して数値の合計を求める方法について解説します。&lt;/p&gt;&#10;&lt;h2 id="背景"&gt;背景&#10;&lt;/h2&gt;&lt;p&gt;シェルスクリプトやコマンドラインで処理するデータには、数値が複数行にわたって出力されることがよくあります。例えば、以下のような出力があるとします：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;65&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;71&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;82&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;82&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;79&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらの数値の合計を求める必要がある場合、AWKを使うことで簡単に処理できます。&lt;/p&gt;&#10;&lt;h2 id="基本コマンド"&gt;基本コマンド&#10;&lt;/h2&gt;&lt;p&gt;以下のコマンドを使用すると、入力データの合計を計算できます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;awk &amp;#39;{sum += $1} END {print sum}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="コマンドの仕組み"&gt;コマンドの仕組み&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;{sum += $1}&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;各行の1列目（&lt;code&gt;$1&lt;/code&gt;）を変数&lt;code&gt;sum&lt;/code&gt;に加算します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;sum&lt;/code&gt;は最初に自動的に0で初期化されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;END {print sum}&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;すべての行を処理し終えた後に&lt;code&gt;END&lt;/code&gt;ブロックが実行され、合計値&lt;code&gt;sum&lt;/code&gt;を出力します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="実例"&gt;実例&#10;&lt;/h2&gt;&lt;h3 id="データの例"&gt;データの例&#10;&lt;/h3&gt;&lt;p&gt;以下のような数値データを持つファイル&lt;code&gt;data.txt&lt;/code&gt;があるとします：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;65&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;71&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;82&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;82&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;79&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このファイルの合計を計算するには、以下のコマンドを実行します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat data.txt | awk &amp;#39;{sum += $1} END {print sum}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="出力結果"&gt;出力結果&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;443&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="findコマンドとの組み合わせ"&gt;&lt;code&gt;find&lt;/code&gt;コマンドとの組み合わせ&#10;&lt;/h3&gt;&lt;p&gt;複数のJSONファイルに対してPythonスクリプトを実行し、その結果の合計を求めるケースを考えます。&lt;/p&gt;&#10;&lt;p&gt;以下のコマンドを使用します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -name &amp;#34;*.json&amp;#34; -exec python a.py {} \; | awk &amp;#39;{sum += $1} END {print sum}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;find&lt;/code&gt;コマンドで&lt;code&gt;.json&lt;/code&gt;ファイルを検索。&lt;/li&gt;&#10;&lt;li&gt;各ファイルに対して&lt;code&gt;python a.py&lt;/code&gt;を実行。&lt;/li&gt;&#10;&lt;li&gt;AWKで出力結果を集計し、合計値を出力。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="出力例"&gt;出力例&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1445&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="応用例"&gt;応用例&#10;&lt;/h2&gt;&lt;p&gt;AWKの&lt;code&gt;sum&lt;/code&gt;変数を応用して、さまざまな計算が可能です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;平均値の計算&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;awk &amp;#39;{sum += $1; count++} END {print sum / count}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;最大値と最小値の計算&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;awk &amp;#39;NR == 1 || $1 &amp;gt; max {max = $1} NR == 1 || $1 &amp;lt; min {min = $1} END {print &amp;#34;Max:&amp;#34;, max, &amp;#34;Min:&amp;#34;, min}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWKはシンプルな構文で強力なテキスト処理を可能にするツールです。特に数値データの合計計算は、短いコマンドで簡単に実現できます。ぜひ活用してみてください！&lt;/p&gt;&#10;</description></item><item><title>[Linux] 一時的にスワップファイルを作成する</title><link>https://ai.hack-le.com/linux-swap-temp/</link><pubDate>Wed, 20 Nov 2024 18:18:16 +0900</pubDate><guid>https://ai.hack-le.com/linux-swap-temp/</guid><description>&lt;p&gt;ビルド時や一時的な高負荷作業でメモリ不足が発生する場合、スワップファイルを一時的に追加することで問題を回避できます。本記事では、一時的なスワップファイルを作成して使用し、作業終了後に削除する手順と、それを効率化するスクリプトをご紹介します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="スワップファイルとは"&gt;スワップファイルとは？&#10;&lt;/h2&gt;&lt;p&gt;スワップファイルは、物理メモリが不足した際にディスク上の領域を仮想メモリとして利用する仕組みです。ただし、ディスクはメモリよりも遅いため、スワップの使用頻度が高いとパフォーマンスに影響を及ぼす可能性があります。そのため、一時的にスワップを増やして高負荷作業を乗り切り、作業終了後に削除する運用が適しています。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="一時的なスワップファイルを作成する手順"&gt;一時的なスワップファイルを作成する手順&#10;&lt;/h2&gt;&lt;h3 id="1-一時的なスワップファイルを作成"&gt;1. 一時的なスワップファイルを作成&#10;&lt;/h3&gt;&lt;p&gt;以下のコマンドで、4GBのスワップファイルを作成します（サイズは用途に応じて変更可能）。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fallocate -l 4G /tmp/swapfile_temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;💡 &lt;code&gt;fallocate&lt;/code&gt;が使用できない場合は、以下のコマンドを使用します:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dd if=/dev/zero of=/tmp/swapfile_temp bs=1M count=4096&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h3 id="2-ファイルの権限を設定"&gt;2. ファイルの権限を設定&#10;&lt;/h3&gt;&lt;p&gt;スワップファイルのセキュリティを確保するため、600の権限を設定します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod 600 /tmp/swapfile_temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h3 id="3-スワップファイルを有効化"&gt;3. スワップファイルを有効化&#10;&lt;/h3&gt;&lt;p&gt;スワップファイルをスワップ領域としてフォーマットし、有効化します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkswap /tmp/swapfile_temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo swapon /tmp/swapfile_temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-スワップ状況を確認"&gt;4. スワップ状況を確認&#10;&lt;/h3&gt;&lt;p&gt;現在のスワップ領域を確認して、追加されたスワップが有効になっているか確認します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;swapon --show&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h3 id="5-作業を実行"&gt;5. 作業を実行&#10;&lt;/h3&gt;&lt;p&gt;ビルドや高負荷の処理を実行します。スワップが有効になっていることで、メモリ不足によるプロセスの停止を回避できます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="6-スワップファイルを無効化"&gt;6. スワップファイルを無効化&#10;&lt;/h3&gt;&lt;p&gt;作業が終了したら、以下のコマンドでスワップファイルを無効化します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo swapoff /tmp/swapfile_temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h3 id="7-スワップファイルを削除"&gt;7. スワップファイルを削除&#10;&lt;/h3&gt;&lt;p&gt;スワップファイルを削除してディスク容量を解放します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm /tmp/swapfile_temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="一時的なスワップファイルを効率化するスクリプト"&gt;一時的なスワップファイルを効率化するスクリプト&#10;&lt;/h2&gt;&lt;p&gt;毎回コマンドを入力するのが手間な場合、スクリプトを作成することで効率化できます。以下のスクリプトは、一時的なスワップを追加・削除する機能を提供します。&lt;/p&gt;&#10;&lt;h3 id="スクリプト-temporary_swapsh"&gt;スクリプト: &lt;code&gt;temporary_swap.sh&lt;/code&gt;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SWAPFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/tmp/swapfile_temp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;4G&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;add&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Adding temporary swap file...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo fallocate -l &lt;span class="nv"&gt;$SIZE&lt;/span&gt; &lt;span class="nv"&gt;$SWAPFILE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo chmod &lt;span class="m"&gt;600&lt;/span&gt; &lt;span class="nv"&gt;$SWAPFILE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo mkswap &lt;span class="nv"&gt;$SWAPFILE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo swapon &lt;span class="nv"&gt;$SWAPFILE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Temporary swap file added.&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;remove&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Removing temporary swap file...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo swapoff &lt;span class="nv"&gt;$SWAPFILE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo rm &lt;span class="nv"&gt;$SWAPFILE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Temporary swap file removed.&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; {add|remove}&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h3 id="スクリプトの使い方"&gt;スクリプトの使い方&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;スクリプトを作成して実行権限を付与します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x temporary_swap.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;スワップファイルを追加するには、以下のコマンドを実行します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./temporary_swap.sh add&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;スワップファイルを削除するには、以下を実行します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./temporary_swap.sh remove&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;一時的なスワップファイルを作成して高負荷作業を安全に乗り切ることができます。&lt;/li&gt;&#10;&lt;li&gt;作業が終了したらスワップファイルを削除することで、ディスク容量を無駄にせずに運用できます。&lt;/li&gt;&#10;&lt;li&gt;スクリプトを活用することで、日々の作業を効率化できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;一時的なスワップファイルの運用は、VPSのようにリソースが限られた環境で特に有効です。ぜひお試しください！&lt;/p&gt;&#10;</description></item><item><title>VSCodeでリモートサーバーのコードをSSH経由で編集する方法</title><link>https://ai.hack-le.com/vscode-remote-ssh/</link><pubDate>Wed, 20 Nov 2024 16:36:45 +0900</pubDate><guid>https://ai.hack-le.com/vscode-remote-ssh/</guid><description>&lt;p&gt;リモートサーバー上のコードをVSCodeで直接編集したいとき、「Remote - SSH」拡張機能を使えば簡単に設定できます。この記事では、その手順を初心者向けにわかりやすく解説します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="-前提条件"&gt;📌 前提条件&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;VSCode&lt;/strong&gt;がインストールされていること。&lt;/li&gt;&#10;&lt;li&gt;SSHでリモートサーバーにアクセスできること（公開鍵認証またはパスワード認証）。&lt;/li&gt;&#10;&lt;li&gt;インターネット接続があること。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="-手順"&gt;📖 手順&#10;&lt;/h2&gt;&lt;h3 id="1-remote---ssh拡張機能をインストール"&gt;1. 「Remote - SSH」拡張機能をインストール&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;VSCodeを起動します。&lt;/li&gt;&#10;&lt;li&gt;左側の「拡張機能」アイコン（四角が飛び出すマーク）をクリックします。&lt;/li&gt;&#10;&lt;li&gt;検索バーに「Remote - SSH」と入力。&lt;/li&gt;&#10;&lt;li&gt;Microsoft製の「Remote - SSH」拡張機能をインストールします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="2-ssh設定ファイルの準備"&gt;2. SSH設定ファイルの準備&#10;&lt;/h3&gt;&lt;p&gt;SSH接続には、&lt;code&gt;~/.ssh/config&lt;/code&gt;ファイルを使用します。この設定ファイルでリモートサーバーへの接続を定義します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;ターミナルを開き、以下のコマンドを実行して設定ファイルを作成または編集します:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano ~/.ssh/config&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;以下のように、リモートサーバーの情報を記述します:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host my-remote-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HostName 192.168.1.100 &lt;span class="c1"&gt;# サーバーのIPまたはホスト名&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User my-username &lt;span class="c1"&gt;# リモートサーバーのユーザー名&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IdentityFile ~/.ssh/id_rsa &lt;span class="c1"&gt;# SSH鍵のパス（鍵認証を使用する場合）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;ファイルを保存して閉じます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;💡 &lt;strong&gt;ヒント&lt;/strong&gt;: &lt;code&gt;Host&lt;/code&gt;の値（例: &lt;code&gt;my-remote-server&lt;/code&gt;）は任意の名前でOK。後で接続時にこの名前を使用します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="3-リモートサーバーに接続"&gt;3. リモートサーバーに接続&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;VSCode左下の緑色の「リモートアイコン」をクリック。&lt;/li&gt;&#10;&lt;li&gt;「Connect to Host」を選択。&lt;/li&gt;&#10;&lt;li&gt;先ほど設定したエイリアス名（例: &lt;code&gt;my-remote-server&lt;/code&gt;）を選択。&lt;/li&gt;&#10;&lt;li&gt;初回接続時に「このホストのSSHキーを信頼するか」と聞かれるので「Yes」を選択。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;リモートサーバーに接続されると、VSCodeのウィンドウが再起動し、リモート環境として動作します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="4-リモートフォルダを開く"&gt;4. リモートフォルダを開く&#10;&lt;/h3&gt;&lt;p&gt;接続後、リモートサーバー上の作業ディレクトリを開きます。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;左側のエクスプローラーで「Open Folder」をクリック。&lt;/li&gt;&#10;&lt;li&gt;リモートサーバー上のディレクトリ（例: &lt;code&gt;/home/my-username/project&lt;/code&gt;）を選択。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;これで、リモートサーバー上のコードがVSCodeで編集可能になります！&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="5-リモート環境での開発"&gt;5. リモート環境での開発&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;リモート環境に必要な拡張機能（例: Python、Node.js関連）をインストールする際は、「Install in SSH: [Host名]」を選択してください。&lt;/li&gt;&#10;&lt;li&gt;ターミナルを開くには、&lt;code&gt;Ctrl +&lt;/code&gt;（バッククォート） ``を押します。リモートサーバーのターミナルが利用できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="-トラブルシューティング"&gt;🛠 トラブルシューティング&#10;&lt;/h2&gt;&lt;h3 id="q1-ssh接続エラーが発生する"&gt;Q1. SSH接続エラーが発生する&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;SSH設定ファイル（&lt;code&gt;~/.ssh/config&lt;/code&gt;）の記述を再確認。&lt;/li&gt;&#10;&lt;li&gt;ターミナルで以下を実行してSSH接続が可能か確認:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh my-remote-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="q2-拡張機能がインストールされない"&gt;Q2. 拡張機能がインストールされない&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;拡張機能画面で「Install in SSH」を選択しているか確認。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="q3-権限エラーが発生"&gt;Q3. 権限エラーが発生&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;リモートサーバー上のファイル・フォルダの権限設定を確認します:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod -R u+w /path/to/directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;これで、リモートサーバーでの開発作業が快適になるはずです！&lt;br&gt;&#10;VSCodeと「Remote - SSH」を使って、効率的なリモート開発を楽しんでください。&lt;/p&gt;&#10;</description></item><item><title>AWS Systems Manager Parameter Storeからパラメータを取得する方法（Python + Boto3）</title><link>https://ai.hack-le.com/aws-systems-manager-parameter-store/</link><pubDate>Sat, 16 Nov 2024 10:57:15 +0900</pubDate><guid>https://ai.hack-le.com/aws-systems-manager-parameter-store/</guid><description>&lt;p&gt;AWS Systems Manager Parameter Storeは、設定データや機密情報（APIキーやパスワードなど）を安全に管理するためのサービスです。本記事では、Pythonを使ってParameter Storeから値を取得する汎用的な方法を解説します。&lt;/p&gt;&#10;&lt;h2 id="必要な準備"&gt;必要な準備&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Python環境の構築&lt;/strong&gt; PythonとAWS SDK for Python（Boto3）がインストールされている必要があります。以下のコマンドでBoto3をインストールします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWSの認証情報と権限&lt;/strong&gt; プログラムを実行する環境に、適切なAWS認証情報が設定されている必要があります（&lt;code&gt;~/.aws/credentials&lt;/code&gt; または環境変数）。また、以下の権限が必要です。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;ssm:GetParameter&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;暗号化された値を取得する場合は、KMSキーの復号化権限（&lt;code&gt;kms:Decrypt&lt;/code&gt;）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Parameter Storeへの登録&lt;/strong&gt; Parameter Storeに取得したい値を登録します。例として、以下のコマンドで値を登録できます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ssm put-parameter \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name &amp;#34;/example/parameter&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --value &amp;#34;my-secret-value&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --type &amp;#34;SecureString&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="汎用的なpythonコードスニペット"&gt;汎用的なPythonコードスニペット&#10;&lt;/h2&gt;&lt;p&gt;以下のコードは、Parameter Storeから値を取得するための汎用的な関数です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;botocore.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BotoCoreError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with_decryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; AWS Systems Manager Parameter Storeからパラメータを取得する汎用関数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Args:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; parameter_name (str): 取得するパラメータの名前&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; with_decryption (bool): 暗号化された値を復号化するかどうか&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Returns:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; str: パラメータの値（取得成功時）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; None: エラー時&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# SSMクライアントの初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ssm_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ssm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# パラメータの取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssm_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;with_decryption&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Parameter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BotoCoreError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Error fetching parameter &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 使用例&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameter_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/parameter&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Parameter value: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to fetch the parameter.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="コードの説明"&gt;コードの説明&#10;&lt;/h2&gt;&lt;h3 id="fetch_parameter-関数の引数"&gt;&lt;code&gt;fetch_parameter&lt;/code&gt; 関数の引数&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;parameter_name&lt;/code&gt; Parameter Storeで登録されているパラメータ名を指定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;with_decryption&lt;/code&gt; 暗号化されたパラメータを復号化するかを指定します。デフォルトは&lt;code&gt;True&lt;/code&gt;（復号化する）です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="例外処理"&gt;例外処理&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;BotoCoreError&lt;/code&gt; および &lt;code&gt;ClientError&lt;/code&gt; は、AWSクライアントでよく発生する例外です。適切にキャッチしてエラー内容をログに記録します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="実行例"&gt;実行例&#10;&lt;/h3&gt;&lt;p&gt;上記のコードを実行すると、Parameter Storeに登録されたパラメータの値が出力されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;認証情報の設定&lt;/strong&gt; AWS CLIの設定が済んでいない場合、以下のコマンドで設定を行います。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;暗号化パラメータの権限&lt;/strong&gt; 暗号化されたパラメータを取得するには、Parameter Storeで使用されているKMSキーに対する&lt;code&gt;kms:Decrypt&lt;/code&gt;権限が必要です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティ&lt;/strong&gt; パラメータ名や値をログに直接記録しないようにしてください（特に値が機密情報の場合）。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="応用例"&gt;応用例&#10;&lt;/h2&gt;&lt;p&gt;この汎用関数を利用して、複数のパラメータをまとめて取得する場合や、環境変数として設定する場合のコード例を示します。&lt;/p&gt;&#10;&lt;h3 id="複数パラメータの取得"&gt;複数パラメータの取得&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;parameter_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/example/param1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/param2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/param3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parameter_names&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to fetch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="環境変数への設定"&gt;環境変数への設定&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/parameter&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;MY_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Environment variable set successfully.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to set environment variable.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS Systems Manager Parameter Storeは、機密情報を安全に管理するための強力なツールです。Pythonでの利用もBoto3を使えば簡単に実現できます。このコードスニペットを活用して、セキュアで柔軟なアプリケーション構築を目指してください。&lt;/p&gt;&#10;</description></item><item><title>LibreOffice Calcでページレイアウトを横向きにする方法 (Mac版英語UI)</title><link>https://ai.hack-le.com/libreoffice-calc-pagelayout-landscape/</link><pubDate>Sat, 19 Oct 2024 16:11:08 +0900</pubDate><guid>https://ai.hack-le.com/libreoffice-calc-pagelayout-landscape/</guid><description>&lt;p&gt;Mac版LibreOffice Calcの英語インターフェースを使用して、スプレッドシートのページレイアウトを横向き（ランドスケープ）に設定する方法を以下にまとめます。&lt;/p&gt;&#10;&lt;h2 id="確認した環境"&gt;確認した環境&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;M2 Pro&#10;&lt;ul&gt;&#10;&lt;li&gt;macOS Sonoma 14.6.1&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;LibreOffice 24.2.5.2 (x86_64)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="手順"&gt;手順&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;「Format」メニューを選択する&lt;/strong&gt; 画面上部のメニューバーから「Format」をクリックします。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「Page Style」を選択する&lt;/strong&gt; 「Format」メニュー内にある「Page Style」をクリックします。これにより、ページのスタイル設定画面が表示されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「Page」タブを開く&lt;/strong&gt; 「Page Style」ダイアログが表示されたら、「Page」タブを選択します。このタブでは、ページの用紙設定や向きなどを調整できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「Orientation」を「Landscape」に変更する&lt;/strong&gt; 「Paper format」セクションにある「Orientation（向き）」の設定で、「Landscape（横向き）」を選択します。「Portrait（縦向き）」から「Landscape（横向き）」へ変更することで、スプレッドシートのレイアウトが横向きになります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「OK」をクリックして設定を適用する&lt;/strong&gt; 設定を変更したら、「OK」をクリックして変更を確定します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2024/10/eda9a9a0fb31189cdbfde91a5e99e9d2-1024x621.jpg"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;Screenshot&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;これでスプレッドシートが横向きに印刷されるように設定されます。&lt;/p&gt;&#10;</description></item><item><title>[Python, Boto3] DynamoDBのクエリで1MBを超えるデータをすべて取得する関数のスニペット</title><link>https://ai.hack-le.com/python-boto3-dynamodb-query/</link><pubDate>Sun, 06 Oct 2024 15:48:30 +0900</pubDate><guid>https://ai.hack-le.com/python-boto3-dynamodb-query/</guid><description>&lt;p&gt;以下は、DynamoDBのクエリで1MBを超えるデータをすべて取得する汎用的な関数のスニペットです。このスニペットは、特定のテーブルや条件に依存しないため、どのプロジェクトでも簡単に利用できます。&lt;/p&gt;&#10;&lt;h2 id="スニペット"&gt;スニペット&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;query_all_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_condition_expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter_expression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; DynamoDBテーブルからすべてのアイテムをクエリし、1MBを超えるデータも取得する。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :param table_name: クエリするテーブルの名前&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :param key_condition_expression: クエリのKeyConditionExpression&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :param filter_expression: オプションのFilterExpression&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :return: すべてのアイテムのリスト&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# DynamoDBクライアントの初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dynamodb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# すべてのアイテムを格納するリスト&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;all_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ページングしてクエリを実行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;KeyConditionExpression&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key_condition_expression&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# FilterExpressionがある場合は追加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;filter_expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;FilterExpression&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filter_expression&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# LastEvaluatedKeyがある場合はExclusiveStartKeyを設定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ExclusiveStartKey&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# クエリの実行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 結果をリストに追加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;all_items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# LastEvaluatedKeyが存在する場合、次のページがある&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LastEvaluatedKey&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 次のページがない場合は終了&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;all_items&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用例"&gt;使用例&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# クエリ条件の定義（例: &amp;#39;partition_key&amp;#39; が &amp;#39;example_value&amp;#39; と等しい）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;key_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;partition_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;example_value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# すべてのアイテムを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_all_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;your_table_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果の出力&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="オプション-filterexpression-の利用"&gt;オプション: &lt;code&gt;FilterExpression&lt;/code&gt; の利用&#10;&lt;/h2&gt;&lt;p&gt;フィルタ条件を追加して、結果をさらに絞り込むことができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# クエリ条件の定義&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;key_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;partition_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;example_value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# フィルタ条件の定義（例: 属性 &amp;#39;status&amp;#39; が &amp;#39;active&amp;#39; のものだけ取得）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;filter_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;active&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# すべてのアイテムを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_all_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;your_table_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter_condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果の出力&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="備考"&gt;備考&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;table_name&lt;/code&gt;: クエリを実行するDynamoDBテーブルの名前。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;key_condition_expression&lt;/code&gt;: プライマリキーの条件式を定義します。パーティションキーとソートキーの条件を設定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;filter_expression&lt;/code&gt;: 結果をさらにフィルタリングするためのオプションの条件式です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このスニペットを活用することで、DynamoDBのすべてのアイテムをクエリしやすくなり、1MB以上のデータを扱う際のページング処理も簡単に行えます。&lt;/p&gt;&#10;</description></item><item><title>JPGなど画像ファイルを圧縮したCBZ,ZIPファイルをPDFに変換する</title><link>https://ai.hack-le.com/zip-cbz-pdf/</link><pubDate>Wed, 25 Sep 2024 12:50:58 +0900</pubDate><guid>https://ai.hack-le.com/zip-cbz-pdf/</guid><description>&lt;p&gt;電子書籍や漫画のフォーマットとしてよく使われる&lt;code&gt;CBZ&lt;/code&gt;ファイルは、実際にはZIP形式で圧縮されたJPEG画像の集まりです。今回は、この&lt;code&gt;CBZ&lt;/code&gt;ファイルを簡単に&lt;code&gt;PDF&lt;/code&gt;に変換する方法を紹介します。&lt;/p&gt;&#10;&lt;p&gt;手順は非常にシンプルで、無料のコマンドラインツールを使って効率よく変換できます。ぜひ試してみてください。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="必要なツール"&gt;必要なツール&#10;&lt;/h2&gt;&lt;p&gt;以下のツールが必要です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;unzip&lt;/code&gt;（通常のZIPファイル解凍に使います）&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;img2pdf&lt;/code&gt;（画像をPDFにまとめるためのツール）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;code&gt;img2pdf&lt;/code&gt;はPythonベースのツールで、簡単にインストールできます。まだインストールしていない場合、次のコマンドを使用してインストールしましょう。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install img2pdf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="手順"&gt;手順&#10;&lt;/h2&gt;&lt;h3 id="cbzファイルを解凍する"&gt;CBZファイルを解凍する&#10;&lt;/h3&gt;&lt;p&gt;まず、&lt;code&gt;.cbz&lt;/code&gt;ファイルを&lt;code&gt;unzip&lt;/code&gt;コマンドで解凍し、中のJPEG画像を取り出します。次のようにコマンドを実行してください。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unzip your_file.cbz -d extracted_images&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;your_file.cbz&lt;/code&gt;は変換したいCBZファイルの名前、&lt;code&gt;extracted_images&lt;/code&gt;は画像を解凍するディレクトリです。&lt;/p&gt;&#10;&lt;h3 id="画像をpdfに変換する"&gt;画像をPDFに変換する&#10;&lt;/h3&gt;&lt;p&gt;次に、解凍されたJPEG画像を1つのPDFファイルにまとめます。&lt;code&gt;img2pdf&lt;/code&gt;コマンドを使って、指定したディレクトリ内のJPEG画像をPDF形式に変換します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;img2pdf extracted_images/*.jpg -o output.pdf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで、&lt;code&gt;output.pdf&lt;/code&gt;という名前のPDFファイルが作成されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="スクリプト化"&gt;スクリプト化&#10;&lt;/h2&gt;&lt;p&gt;次のようなBashスクリプトを作成すれば、&lt;code&gt;.cbz&lt;/code&gt;ファイルをPDFに変換し、同じファイル名のPDFを出力し、途中で生成された不要なファイルを削除できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CBZファイルを引数として受け取る&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; filename.cbz&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ファイル名とディレクトリを分離&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;cbz_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;basename &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cbz_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; .cbz&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;directory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dirname &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cbz_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 一時ディレクトリを作成&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;temp_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp -d&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CBZファイルを解凍&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unzip &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cbz_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$temp_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 画像ファイルをPDFに変換&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;img2pdf &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$temp_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;/*.jpg -o &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$directory&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;.pdf&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 一時ディレクトリを削除&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$temp_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Conversion completed: &lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;.pdf&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;以上で、CBZファイルを簡単にPDFに変換できる手順を紹介しました。特別なソフトウェアは必要なく、コマンドラインだけでサクッと変換できるので、ぜひこの方法を活用してください。漫画や電子書籍をPDF化して整理したい方にぴったりの方法です。&lt;/p&gt;&#10;</description></item><item><title>AWS SAMでLambda関数をスケジュール実行する</title><link>https://ai.hack-le.com/aws-sam-lambda-schedule/</link><pubDate>Wed, 25 Sep 2024 00:27:32 +0900</pubDate><guid>https://ai.hack-le.com/aws-sam-lambda-schedule/</guid><description>&lt;p&gt;AWS LambdaをAWS SAM（Serverless Application Model）で管理する際に、特定の間隔で定期的に実行されるようにスケジュール設定する方法について説明します。たとえば、10分ごとにLambda関数を起動したい場合に、どのように設定するかを見ていきます。&lt;/p&gt;&#10;&lt;h2 id="samテンプレートにスケジュールイベントを追加"&gt;SAMテンプレートにスケジュールイベントを追加&#10;&lt;/h2&gt;&lt;p&gt;まず、既存のSAMテンプレートに新しいイベントを追加します。今回は、&lt;code&gt;AWS::Serverless::Function&lt;/code&gt;リソースにスケジュールイベントを設定する例を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;MyFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS::Serverless::Function&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;src/my_lambda.lambda_handler&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="l"&gt;GetAtt MyLambdaRole.Arn&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POWERTOOLS_SERVICE_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;MyFunction&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;HttpRequestEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;HttpApi&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ApiId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="l"&gt;Ref MyApiGateway&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/myendpoint&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;get&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ScheduleEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Schedule&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rate(10 minutes)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="schedule-イベントの詳細"&gt;&lt;code&gt;Schedule&lt;/code&gt; イベントの詳細&#10;&lt;/h2&gt;&lt;p&gt;この例では、既存のLambda関数に &lt;code&gt;Schedule&lt;/code&gt; イベントを追加しています。具体的には、以下の点に注目してください。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;Type: Schedule&lt;/code&gt;：これは、Lambda関数が定期的に実行されるようにするための設定です。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;Schedule: rate(10 minutes)&lt;/code&gt;：10分ごとに実行されるように指定しています。AWSでは、&lt;code&gt;rate&lt;/code&gt; 式や &lt;code&gt;cron&lt;/code&gt; 式を使用してスケジュールを定義できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="rate-式の使用例"&gt;&lt;code&gt;rate&lt;/code&gt; 式の使用例&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;rate&lt;/code&gt; 式を使うことで、簡単にスケジュールを定義できます。例えば、以下のようなスケジュールが設定できます：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1時間ごとに実行したい場合:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: rate(1 hour)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;1日ごとに実行したい場合:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: rate(1 day)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;rate&lt;/code&gt; 式は短い間隔で繰り返し実行する場合に便利です。&lt;/p&gt;&#10;&lt;h3 id="cron-式の使用例"&gt;&lt;code&gt;cron&lt;/code&gt; 式の使用例&#10;&lt;/h3&gt;&lt;p&gt;より複雑なスケジュールが必要な場合は、&lt;code&gt;cron&lt;/code&gt; 式を使用することもできます。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;cron&lt;/code&gt; 式は、定期的なスケジュールを指定するための強力なツールで、より細かい制御が可能です。AWSで使用される &lt;code&gt;cron&lt;/code&gt; 式は、5つまたは6つのフィールドで構成され、それぞれのフィールドが特定の時間単位を表します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cron(Minutes Hours Day-of-month Month Day-of-week Year)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各フィールドの意味は以下の通りです：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Minutes (0-59)&lt;/strong&gt; : 分単位。0から59の間で指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Hours (0-23)&lt;/strong&gt; : 時間単位。0から23の間で指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Day-of-month (1-31)&lt;/strong&gt; : 月の日。1から31の間で指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Month (1-12)&lt;/strong&gt; : 月。1月が1、12月が12です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Day-of-week (1-7)&lt;/strong&gt; : 曜日。日曜日が1、土曜日が7です（またはSUN, MONなどの省略形が使えます）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Year (オプション)&lt;/strong&gt; : 年単位。省略可能ですが、指定する場合は4桁で記述します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;以下に、よく使われる &lt;code&gt;cron&lt;/code&gt; 式の例をいくつか示します。&lt;/p&gt;&#10;&lt;h4 id="毎日午前9時に実行"&gt;毎日午前9時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 9 * * ? *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎日午前9時にLambda関数を実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 分は0、時間は9（午前9時）、日・月・曜日はすべての値（&lt;code&gt;*&lt;/code&gt;）、特定の年は指定しない。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="毎月1日午前8時に実行"&gt;毎月1日午前8時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 8 1 * ? *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎月1日の午前8時に実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 毎月の1日に分0、午前8時に実行します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="平日の毎日午後1時に実行"&gt;平日の毎日午後1時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 13 ? * MON-FRI *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 平日（月曜〜金曜）の毎日午後1時に実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 分0、午後1時、曜日は月曜から金曜（&lt;code&gt;MON-FRI&lt;/code&gt;）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="週末の毎日午前10時に実行"&gt;週末の毎日午前10時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 10 ? * SAT,SUN *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎週土曜日と日曜日の午前10時に実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 分0、午前10時、曜日は土曜日と日曜日。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="毎時30分に実行"&gt;毎時30分に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(30 * * * ? *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎時30分にLambda関数を実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 毎時間の30分に実行（時間は全ての値）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="cron式のワイルドカード-と--の使い分け"&gt;cron式のワイルドカード&lt;code&gt;?&lt;/code&gt; と &lt;code&gt;*&lt;/code&gt; の使い分け&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;cron&lt;/code&gt; 式で使われる &lt;code&gt;*&lt;/code&gt; と &lt;code&gt;?&lt;/code&gt; は、どちらもワイルドカードとして機能しますが、使用場所に違いがあります。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;*&lt;/code&gt;&lt;/strong&gt; : すべての値を指定するために使用します。たとえば、&lt;code&gt;Minutes&lt;/code&gt; フィールドが &lt;code&gt;*&lt;/code&gt; なら「毎分」を意味します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;?&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;Day-of-month&lt;/code&gt; または &lt;code&gt;Day-of-week&lt;/code&gt; フィールドでのみ使用でき、「特定しない」という意味です。これにより、日または曜日のどちらかに特定の値を設定しない場合に使用します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS SAMを使用してLambda関数を10分ごとなどの定期的な間隔で実行する設定は非常に簡単です。&lt;code&gt;rate&lt;/code&gt; 式や &lt;code&gt;cron&lt;/code&gt; 式を利用して、ニーズに応じたスケジュールを柔軟に設定できます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="参考資料"&gt;参考資料&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html" target="_blank" rel="noopener"&#10; &gt;AWS Lambda - Schedule expressions&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html" target="_blank" rel="noopener"&#10; &gt;AWS SAM Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>AWS Lambda Layers に特定のリポジトリからライブラリをアップロードする</title><link>https://ai.hack-le.com/aws-lambda-layers-repository/</link><pubDate>Sat, 21 Sep 2024 10:20:34 +0900</pubDate><guid>https://ai.hack-le.com/aws-lambda-layers-repository/</guid><description>&lt;p&gt;AWS Lambda Layers を利用することで、Lambda 関数の依存関係を外部化し、関数のデプロイパッケージをシンプルに保つことができます。本記事では、特定の Git リポジトリから取得したライブラリを AWS Lambda Layers にアップロードする手順を解説します。&lt;/p&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;p&gt;以下のツールがインストールされていることを確認してください。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Python 3.x&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;pip&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;AWS CLI&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;zip&lt;/code&gt; コマンド&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="lambda-layer-用のディレクトリ構造を作成"&gt;Lambda Layer 用のディレクトリ構造を作成&#10;&lt;/h2&gt;&lt;p&gt;Lambda Layer 用に、ライブラリをインストールするディレクトリを作成します。Lambda Layers は、このディレクトリ内にライブラリを配置することで、Lambda 関数がそれらを参照できるようにします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;python&lt;/code&gt; ディレクトリが Layer にアップロードされる場所です。この中にライブラリをインストールしていきます。&lt;/p&gt;&#10;&lt;h2 id="git-リポジトリからライブラリをインストール"&gt;Git リポジトリからライブラリをインストール&#10;&lt;/h2&gt;&lt;p&gt;次に、&lt;code&gt;pip&lt;/code&gt; を使って特定の Git リポジトリからライブラリを &lt;code&gt;python&lt;/code&gt; ディレクトリ内にインストールします。例えば、特定のコミットハッシュやブランチを指定してライブラリを取得したい場合、以下のようなコマンドを使います。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install git+https://&amp;lt;リポジトリのURL&amp;gt;@&amp;lt;コミットハッシュまたはブランチ名&amp;gt; -t python/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&amp;lt;リポジトリのURL&amp;gt;&lt;/code&gt; は対象ライブラリの Git リポジトリ URL を指定し、&lt;code&gt;&amp;lt;コミットハッシュまたはブランチ名&amp;gt;&lt;/code&gt; には特定のバージョンやブランチを指定します。&lt;/p&gt;&#10;&lt;h2 id="不要なファイルを削除オプション"&gt;不要なファイルを削除（オプション）&#10;&lt;/h2&gt;&lt;p&gt;インストールしたライブラリには、不要なファイル（例：ドキュメントやテストファイル）が含まれることがあります。Lambda Layers のサイズを抑えるために、以下のコマンドで不要なファイルを削除します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find python/ -name &amp;#34;*.dist-info&amp;#34; -exec rm -r {} +&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find python/ -name &amp;#34;*.egg-info&amp;#34; -exec rm -r {} +&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="layer-の-zip-ファイルを作成"&gt;Layer の ZIP ファイルを作成&#10;&lt;/h2&gt;&lt;p&gt;次に、&lt;code&gt;python&lt;/code&gt; ディレクトリを ZIP ファイルに圧縮します。この ZIP ファイルが、AWS Lambda にアップロードされる Layer の内容になります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zip -r layer.zip python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで Layer の準備が整いました。&lt;/p&gt;&#10;&lt;h2 id="aws-lambda-layer-にアップロード"&gt;AWS Lambda Layer にアップロード&#10;&lt;/h2&gt;&lt;p&gt;AWS CLI を使って、作成した ZIP ファイルを AWS Lambda Layer にアップロードします。以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda publish-layer-version \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --layer-name &amp;lt;Layer名&amp;gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --description &amp;#34;Lambda Layer for custom libraries&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --zip-file fileb://layer.zip \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --compatible-runtimes python3.x \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --region &amp;lt;リージョン名&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;&amp;lt;Layer名&amp;gt;&lt;/code&gt; には Layer の名前を指定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;&amp;lt;リージョン名&amp;gt;&lt;/code&gt; には AWS のリージョンを指定します（例：&lt;code&gt;ap-northeast-1&lt;/code&gt; など）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このコマンドを実行すると、Layer の ARN（Amazon リソースネーム）が返されます。この ARN を後で Lambda 関数に設定します。&lt;/p&gt;&#10;&lt;h2 id="lambda-関数に-layer-を追加"&gt;Lambda 関数に Layer を追加&#10;&lt;/h2&gt;&lt;p&gt;Layer を作成した後、それを Lambda 関数で使用できるようにします。以下はSAMの&lt;code&gt;template.yaml&lt;/code&gt; での例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Globals:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Function:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; CodeUri: src&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Runtime: python3.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Timeout: 30&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MemorySize: 256&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Layers:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - arn:aws:lambda:&amp;lt;リージョン名&amp;gt;:&amp;lt;アカウントID&amp;gt;:layer:&amp;lt;Layer名&amp;gt;:&amp;lt;バージョン番号&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Variables:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; TABLE_NAME: &amp;#34;example_table&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&amp;lt;リージョン名&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;アカウントID&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Layer名&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;バージョン番号&amp;gt;&lt;/code&gt; は、AWS CLI で Layer を作成した際に取得した情報を入力してください。&lt;/p&gt;&#10;&lt;h2 id="デプロイして動作確認"&gt;デプロイして動作確認&#10;&lt;/h2&gt;&lt;p&gt;Layer を Lambda 関数に追加したら、通常通りに関数をビルドしてデプロイします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sam build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sam deploy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;デプロイ後、関数が正しく Layer を参照して動作しているか確認します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS Lambda Layers を使用することで、Lambda 関数に依存関係を簡単に管理し、ライブラリの一元管理や再利用が可能になります。特定の Git リポジトリからライブラリを取得して Layer にアップロードすることで、より柔軟な開発環境を構築できるようになります。&lt;/p&gt;&#10;</description></item><item><title>macOSのlaunchdでスクリプトを定期実行するplistのメモ</title><link>https://ai.hack-le.com/macos-launchd-schedule/</link><pubDate>Tue, 10 Sep 2024 14:41:02 +0900</pubDate><guid>https://ai.hack-le.com/macos-launchd-schedule/</guid><description>&lt;h2 id="macosのlaunchdでスクリプトを定期実行する方法"&gt;macOSの&lt;code&gt;launchd&lt;/code&gt;でスクリプトを定期実行する方法&#10;&lt;/h2&gt;&lt;p&gt;macOSの&lt;code&gt;launchd&lt;/code&gt;は、特定の時間に自動でスクリプトを実行するために利用できる便利な機能です。今回は、毎朝3時15分にバックアップスクリプトを実行するための&lt;code&gt;plist&lt;/code&gt;ファイルの例とその解説を紹介します。&lt;/p&gt;&#10;&lt;p&gt;必要なPATHをとおしたり標準出力、エラー出力の設定が便利です。&lt;/p&gt;&#10;&lt;h3 id="設定ファイルplistの内容"&gt;設定ファイル（&lt;code&gt;plist&lt;/code&gt;）の内容&#10;&lt;/h3&gt;&lt;p&gt;まず、以下は&lt;code&gt;launchd&lt;/code&gt;用の&lt;code&gt;plist&lt;/code&gt;ファイルの例です。このファイルを使って、指定したスクリプトを毎日指定した時間に実行できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34; &amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;plist version=&amp;#34;1.0&amp;#34;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;!-- Labelは一意の識別子です。重複しないように適切な名前を指定してください --&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;com.example.backup-task&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;!-- ProgramArgumentsは実行したいスクリプトのパスを指定します --&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/Users/username/scripts/backup-task.sh&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;/array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;!-- EnvironmentVariablesで必要な環境変数を指定します。PATH変数を設定 --&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;EnvironmentVariables&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;PATH&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;/dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;!-- RunAtLoadはシステム起動時にスクリプトを実行するかを指定します --&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;false/&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;!-- StandardOutPathとStandardErrorPathでログの出力先を指定します --&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;StandardOutPath&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/tmp/backup-task.log&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;StandardErrorPath&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/tmp/backup-task-error.log&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;!-- StartCalendarIntervalで実行タイミングを指定します。毎日3時15分に実行 --&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;StartCalendarInterval&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;Hour&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;integer&amp;gt;3&amp;lt;/integer&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;Minute&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;integer&amp;gt;15&amp;lt;/integer&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;/dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/plist&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="設定ファイルの各部分の解説"&gt;設定ファイルの各部分の解説&#10;&lt;/h3&gt;&lt;h4 id="label"&gt;Label&#10;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;&amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&lt;/code&gt; には、この&lt;code&gt;launchd&lt;/code&gt;ジョブの一意な識別子を指定します。他のジョブと名前が重複しないように注意が必要です。この例では&lt;code&gt;com.example.backup-task&lt;/code&gt;を使っていますが、適切な名前に変更してください。&lt;/p&gt;&#10;&lt;h4 id="programarguments"&gt;ProgramArguments&#10;&lt;/h4&gt;&lt;p&gt;ここには実行するスクリプトの絶対パスを指定します。この例では&lt;code&gt;/Users/username/scripts/backup-task.sh&lt;/code&gt;となっていますが、実際のスクリプトのパスに置き換えてください。&lt;/p&gt;&#10;&lt;h4 id="environmentvariables"&gt;EnvironmentVariables&#10;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;launchd&lt;/code&gt;はデフォルトでユーザの環境変数を引き継ぎません。そのため、必要に応じて&lt;code&gt;PATH&lt;/code&gt;などの環境変数を明示的に設定する必要があります。ここでは、一般的な&lt;code&gt;PATH&lt;/code&gt;を指定していますが、必要に応じてカスタマイズしてください。&lt;/p&gt;&#10;&lt;h4 id="runatload"&gt;RunAtLoad&#10;&lt;/h4&gt;&lt;p&gt;システム起動時にスクリプトを実行したい場合は、このキーを&lt;code&gt;true&lt;/code&gt;に設定します。起動時の実行が不要な場合は&lt;code&gt;false&lt;/code&gt;に設定します。&lt;/p&gt;&#10;&lt;h4 id="standardoutpathとstandarderrorpath"&gt;StandardOutPathとStandardErrorPath&#10;&lt;/h4&gt;&lt;p&gt;スクリプトの実行結果やエラーのログを指定されたファイルに出力します。これにより、スクリプトが正しく実行されているか、エラーが発生した場合に調査が容易になります。&lt;code&gt;/tmp/&lt;/code&gt;ディレクトリにログを出力するように設定していますが、適宜変更してください。&lt;/p&gt;&#10;&lt;h4 id="startcalendarinterval"&gt;StartCalendarInterval&#10;&lt;/h4&gt;&lt;p&gt;この部分で、実行タイミングを設定します。&lt;code&gt;Hour&lt;/code&gt;を&lt;code&gt;3&lt;/code&gt;、&lt;code&gt;Minute&lt;/code&gt;を&lt;code&gt;15&lt;/code&gt;に設定することで、毎朝3時15分にスクリプトが実行されるようにしています。希望の時間に変更してください。&lt;/p&gt;&#10;&lt;h3 id="設定ファイルを有効にする"&gt;設定ファイルを有効にする&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;上記の内容をテキストエディタで編集し、&lt;code&gt;~/Library/LaunchAgents/com.example.backup-task.plist&lt;/code&gt;として保存します。名前は適宜変更可能です。&lt;/li&gt;&#10;&lt;li&gt;次に、以下のコマンドをターミナルで実行して、&lt;code&gt;launchd&lt;/code&gt;にジョブを読み込ませます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl load ~/Library/LaunchAgents/com.example.backup-task.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで、毎日指定した時間にスクリプトが自動的に実行されるようになります。ジョブを停止したい場合は、以下のコマンドでアンロードできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl unload ~/Library/LaunchAgents/com.example.backup-task.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;launchd&lt;/code&gt;を使うことで、定期的に実行したいスクリプトやタスクを簡単にスケジュールすることができます。環境変数の設定やログの出力設定など、細かいカスタマイズも可能なので、自分の環境に合わせて調整してください。&lt;/p&gt;&#10;</description></item><item><title>コンテナでAWS認証情報を安全に渡す方法 – 環境変数を使った手軽なアプローチ</title><link>https://ai.hack-le.com/container-aws/</link><pubDate>Sun, 08 Sep 2024 11:57:22 +0900</pubDate><guid>https://ai.hack-le.com/container-aws/</guid><description>&lt;p&gt;AWSのリソース（例：DynamoDBやSecrets Manager）を操作するアプリケーションをコンテナで実行する場合、認証情報（&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; や &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;）をコンテナ内にどのように渡すかが重要です。特に、手軽で一般的な方法として &lt;strong&gt;環境変数&lt;/strong&gt; を利用する方法があります。この記事では、環境変数を使った認証情報の渡し方と、その際のセキュリティ上の注意点について解説します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="環境変数を使って認証情報を渡す"&gt;環境変数を使って認証情報を渡す&#10;&lt;/h2&gt;&lt;p&gt;AWS認証情報を渡す最も簡単な方法は、環境変数を使うことです。これにより、コード内に直接認証情報をハードコードする必要がなくなります。次のようにDockerを実行する際に &lt;code&gt;-e&lt;/code&gt; オプションを使って認証情報を渡せます。&lt;/p&gt;&#10;&lt;h3 id="dockerを使った実行例"&gt;Dockerを使った実行例&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_access_key_id &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_secret_access_key &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e &lt;span class="nv"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_region &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; your_image_name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;また、認証情報を &lt;code&gt;.env&lt;/code&gt; ファイルにまとめて管理することもできます。&lt;/p&gt;&#10;&lt;h3 id="env-ファイルの例"&gt;&lt;code&gt;.env&lt;/code&gt; ファイルの例&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_access_key_id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_secret_access_key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_region&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker実行時にこの &lt;code&gt;.env&lt;/code&gt; ファイルを読み込ませます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --env-file .env your_image_name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;環境変数を使うことで、シンプルかつ手軽にAWS認証情報をコンテナに渡せますが、次のようなセキュリティに関する注意点があります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="セキュリティ上の注意点"&gt;セキュリティ上の注意点&#10;&lt;/h2&gt;&lt;p&gt;環境変数は簡単で便利な方法ですが、適切に管理しなければセキュリティリスクがあります。以下は、環境変数を使う際に意識しておきたい主なポイントです。&lt;/p&gt;&#10;&lt;h3 id="環境変数の漏洩リスク"&gt;環境変数の漏洩リスク&#10;&lt;/h3&gt;&lt;p&gt;環境変数にAWSの認証情報を設定する場合、それが &lt;strong&gt;ログに出力されないように注意&lt;/strong&gt; する必要があります。誤って認証情報がログに残ると、悪意のある第三者がアクセスできるリスクが高まります。例えば、システムやアプリケーションのログで環境変数が出力される設定になっていないか確認しましょう。&lt;/p&gt;&#10;&lt;h3 id="アクセス制御の強化"&gt;アクセス制御の強化&#10;&lt;/h3&gt;&lt;p&gt;コンテナをホストしているVPSへの &lt;strong&gt;アクセス権限を制御&lt;/strong&gt; することも非常に重要です。VPSにアクセスできるユーザーが多い場合、誰でも環境変数にアクセスできる可能性があります。SSHの鍵管理やファイルシステムの権限設定などを適切に行い、限られたユーザーだけがアクセスできるようにしましょう。&lt;/p&gt;&#10;&lt;h3 id="長期運用時の考慮"&gt;長期運用時の考慮&#10;&lt;/h3&gt;&lt;p&gt;開発環境や小規模なプロジェクトでは環境変数での管理は問題ないですが、長期的に運用する場合や規模が大きくなる場合は、IAMロールやAWSの &lt;strong&gt;セキュリティトークンサービス (STS)&lt;/strong&gt; などの高度な管理方法を検討するべきです。これにより、認証情報の自動ローテーションや、一時的なトークンの使用が可能になります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="改善ポイントセキュリティを強化する方法"&gt;改善ポイント：セキュリティを強化する方法&#10;&lt;/h2&gt;&lt;p&gt;環境変数を使う方法自体は手軽で問題ありませんが、セキュリティを向上させるために以下の対策を取ることをおすすめします。&lt;/p&gt;&#10;&lt;h3 id="env-ファイルのバージョン管理を避ける"&gt;&lt;code&gt;.env&lt;/code&gt; ファイルのバージョン管理を避ける&#10;&lt;/h3&gt;&lt;p&gt;認証情報が含まれる &lt;code&gt;.env&lt;/code&gt; ファイルは &lt;strong&gt;バージョン管理システム（例：Git）に含めない&lt;/strong&gt; ようにしましょう。&lt;code&gt;.gitignore&lt;/code&gt; に &lt;code&gt;.env&lt;/code&gt; を追加し、誤ってリポジトリにプッシュされるのを防ぐことが重要です。&lt;/p&gt;&#10;&lt;h3 id="最小権限の原則に従う"&gt;最小権限の原則に従う&#10;&lt;/h3&gt;&lt;p&gt;DynamoDBやSecrets ManagerにアクセスするためのAWSユーザーには、必要最低限の権限だけを付与しましょう。例えば、DynamoDBへの読み取りと書き込みの権限、Secrets Managerへの読み取り権限など、&lt;strong&gt;最小限のIAMポリシー&lt;/strong&gt; を設定します。&lt;/p&gt;&#10;&lt;h3 id="認証情報のローテーション"&gt;認証情報のローテーション&#10;&lt;/h3&gt;&lt;p&gt;認証情報は定期的に &lt;strong&gt;ローテーション（更新）&lt;/strong&gt; することを検討してください。長期間にわたり同じキーを使い続けると、万が一流出した際のリスクが増大します。AWSでは、IAMユーザーのアクセスキーのローテーションを簡単に設定できます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;環境変数を使ってAWSの認証情報をコンテナに渡す方法は、特に小規模なプロジェクトや開発環境では &lt;strong&gt;手軽で一般的&lt;/strong&gt; なアプローチです。ただし、セキュリティを考慮して、環境変数が漏洩しないように管理し、アクセス権限やファイル管理を適切に行うことが重要です。また、長期的な運用環境ではIAMロールや認証情報のローテーションなど、よりセキュアな方法を導入することも検討する価値があります。&lt;/p&gt;&#10;&lt;p&gt;安全かつ効率的なAWSリソースの操作を目指して、正しい認証情報の管理を心がけましょう。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="参考資料"&gt;参考資料&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_create-console.html" target="_blank" rel="noopener"&#10; &gt;AWS IAM ポリシーの作成&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/intro.html" target="_blank" rel="noopener"&#10; &gt;AWS Secrets Manager の利用方法&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html" target="_blank" rel="noopener"&#10; &gt;AWS CLI 認証情報の管理&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Dockerインストール後のpermission deniedエラーの解決方法</title><link>https://ai.hack-le.com/docker-permission-denied/</link><pubDate>Wed, 28 Aug 2024 16:59:23 +0900</pubDate><guid>https://ai.hack-le.com/docker-permission-denied/</guid><description>&lt;p&gt;DockerをUbuntuにインストールした後、&lt;code&gt;docker build&lt;/code&gt;などのコマンドを実行すると、以下のようなエラーメッセージが表示されることがあります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: &amp;lt;br&amp;gt;Post &amp;#34;http://%2Fvar%2Frun%2Fdocker.sock/v1.24/build?buildargs=%7B%7D&amp;amp;cachefrom=%5B%5D&amp;amp;cgroupparent=&amp;amp;cpuperiod=0&amp;amp;cpuquota=0&amp;amp;cpusetcpus=&amp;amp;cpusetmems=&amp;amp;cpushares=0&amp;amp;dockerfile=Dockerfile&amp;amp;labels=%7B%7D&amp;amp;memory=0&amp;amp;memswap=0&amp;amp;networkmode=default&amp;amp;rm=1&amp;amp;shmsize=0&amp;amp;t=apptest&amp;amp;target=&amp;amp;ulimits=null&amp;amp;version=1&amp;#34;: dial unix /var/run/docker.sock: connect: permission denied&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このエラーは、Dockerデーモンにアクセスするための権限が不足しているために発生します。&lt;/p&gt;&#10;&lt;h2 id="原因"&gt;原因&#10;&lt;/h2&gt;&lt;p&gt;Dockerは、デフォルトで&lt;code&gt;/var/run/docker.sock&lt;/code&gt;というUnixソケットを介してデーモンと通信します。このソケットにアクセスするには、適切な権限が必要です。通常、&lt;code&gt;docker&lt;/code&gt;グループにユーザーが所属していない場合にこのエラーが発生します。&lt;/p&gt;&#10;&lt;h2 id="解決方法"&gt;解決方法&#10;&lt;/h2&gt;&lt;h3 id="dockerグループにユーザーを追加する"&gt;Dockerグループにユーザーを追加する&#10;&lt;/h3&gt;&lt;p&gt;最も推奨される方法は、&lt;code&gt;docker&lt;/code&gt;グループに現在のユーザーを追加することです。これにより、管理者権限なしでDockerコマンドを実行できるようになります。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;ユーザーを&lt;code&gt;docker&lt;/code&gt;グループに追加&lt;/strong&gt;: 以下のコマンドを実行して、現在のユーザーを&lt;code&gt;docker&lt;/code&gt;グループに追加します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo usermod -aG docker $USER&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;変更を反映させる&lt;/strong&gt;: ユーザーを&lt;code&gt;docker&lt;/code&gt;グループに追加した後、シェルセッションを再起動するか、以下のコマンドを実行して変更を反映させます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;newgrp docker&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;動作確認&lt;/strong&gt;: 変更が適用されたかを確認するために、再度&lt;code&gt;docker build&lt;/code&gt;などのコマンドを実行してみてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker build -t タグ名 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正しく動作すれば、&lt;code&gt;permission denied&lt;/code&gt;エラーが解消されているはずです。&lt;/p&gt;&#10;&lt;h3 id="sudoを使ってコマンドを実行するオプション"&gt;&lt;code&gt;sudo&lt;/code&gt;を使ってコマンドを実行する（オプション）&#10;&lt;/h3&gt;&lt;p&gt;もし&lt;code&gt;docker&lt;/code&gt;グループにユーザーを追加したくない場合、&lt;code&gt;sudo&lt;/code&gt;を使ってDockerコマンドを実行することも可能です。ただし、毎回&lt;code&gt;sudo&lt;/code&gt;を使用する必要があるため、効率が低下する可能性があります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo docker build -t タグ名 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>ファイル名に数字の部分があったら、桁数を引数で指定してゼロ埋めするbashスクリプト</title><link>https://ai.hack-le.com/file-zeropadding-script/</link><pubDate>Mon, 12 Aug 2024 16:08:18 +0900</pubDate><guid>https://ai.hack-le.com/file-zeropadding-script/</guid><description>&lt;p&gt;この記事では、ファイル名に含まれる数字部分を指定した桁数でゼロ埋めするBashスクリプトを紹介し、その技術的な詳細を解説します。このスクリプトは、数字部分を柔軟に処理し、デフォルトで4桁、引数を指定することで任意の桁数でゼロ埋めすることができます。MacやLinux環境で動作し、ファイル名の管理や整理を効率的に行えます。&lt;/p&gt;&#10;&lt;h2 id="スクリプトの概要"&gt;スクリプトの概要&#10;&lt;/h2&gt;&lt;p&gt;このスクリプトは、ディレクトリ内のすべてのファイルを対象にして、ファイル名に含まれる数字部分を指定された桁数でゼロ埋めします。ゼロ埋めの桁数は、スクリプトの引数として指定することができ、引数が指定されない場合はデフォルトで4桁になります。&lt;/p&gt;&#10;&lt;h2 id="スクリプト全文"&gt;スクリプト全文&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ゼロ埋めする桁数を引数から取得、デフォルトは4桁&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;pad_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;4&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ディレクトリ内のすべてのファイルを処理する&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ファイル名を変数に格納&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;original_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ファイル名の各部分をチェック&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; -r -n1 char&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$char&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$number$char&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 8進数の解釈を避けるため、整数として扱う&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;10#&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; -le &lt;span class="nv"&gt;$pad_length&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%0&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pad_length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;d&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$modified_name$char&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$original_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 末尾に数字があった場合、それをゼロ埋めする&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;10#&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; -le &lt;span class="nv"&gt;$pad_length&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%0&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pad_length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;d&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;modified_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 名前が変更されていればファイル名を変更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$original_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$modified_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$original_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$modified_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Renamed: &lt;/span&gt;&lt;span class="nv"&gt;$original_name&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$modified_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="技術的な解説"&gt;技術的な解説&#10;&lt;/h2&gt;&lt;h3 id="引数による桁数の指定"&gt;引数による桁数の指定&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;pad_length=${1:-4}&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;この部分は、スクリプトに渡された引数を &lt;code&gt;pad_length&lt;/code&gt; という変数に代入しています。引数が指定されなかった場合には、デフォルトで4桁が使用されます。これにより、ユーザーは必要に応じて任意の桁数でゼロ埋めが可能です。&lt;/p&gt;&#10;&lt;h3 id="ファイル名の処理"&gt;ファイル名の処理&#10;&lt;/h3&gt;&lt;p&gt;スクリプトは、&lt;code&gt;for file in *; do&lt;/code&gt; ループを使って、現在のディレクトリ内にあるすべてのファイルを順番に処理します。ファイル名の各文字を1文字ずつチェックし、数字部分を検出してゼロ埋めを行います。&lt;/p&gt;&#10;&lt;h3 id="8進数の解釈を回避"&gt;8進数の解釈を回避&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;number=$((10#$number))&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;printf&lt;/code&gt; コマンドは、数字の先頭にゼロがついていると、それを8進数として解釈しようとします。このため、先頭のゼロを取り除いてから処理を行う必要があります。この行で &lt;code&gt;number&lt;/code&gt; 変数を整数に変換し、8進数の誤解釈を回避しています。&lt;/p&gt;&#10;&lt;h3 id="printf-を使ったゼロ埋め"&gt;&lt;code&gt;printf&lt;/code&gt; を使ったゼロ埋め&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;modified_name=&amp;quot;${modified_name}$(printf &amp;quot;%0${pad_length}d&amp;quot; &amp;quot;$number&amp;quot;)&amp;quot;&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;この部分で、&lt;code&gt;printf&lt;/code&gt; コマンドを使用して、指定された桁数で数字をゼロ埋めしています。&lt;code&gt;${pad_length}&lt;/code&gt; によってゼロ埋めする桁数が動的に決定されます。&lt;/p&gt;&#10;&lt;h3 id="ファイル名の変更"&gt;ファイル名の変更&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;mv &amp;quot;$original_name&amp;quot; &amp;quot;$modified_name&amp;quot;&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;最後に、元のファイル名とゼロ埋めされた新しいファイル名を比較し、異なる場合は&lt;code&gt;mv&lt;/code&gt;コマンドを使用してファイル名を変更します。これにより、ファイルが適切にリネームされ、処理が完了します。&lt;/p&gt;&#10;&lt;h2 id="使用例"&gt;使用例&#10;&lt;/h2&gt;&lt;p&gt;このスクリプトを利用する際の基本的な実行例を以下に示します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;デフォルトで4桁ゼロ埋めを行う場合：&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./rename_files.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;6桁でゼロ埋めを行いたい場合：&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./rename_files.sh 6&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このようにして、任意の桁数で数字部分をゼロ埋めすることができます。ファイル名に含まれる複数の数字部分にも対応しており、ファイル管理の際に役立つツールとなるでしょう。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;このスクリプトは、Bashでのファイル名処理を強力かつ柔軟に行うための便利なツールです。MacやLinuxの環境でスムーズに動作し、シンプルなコマンドでファイル名の数字部分を整形することができます。ぜひ、ご自身のプロジェクトで活用してみてください。&lt;/p&gt;&#10;</description></item><item><title>ディレクトリベースで複数のGitHubアカウントを管理する方法</title><link>https://ai.hack-le.com/directory-github/</link><pubDate>Thu, 04 Jul 2024 18:56:23 +0900</pubDate><guid>https://ai.hack-le.com/directory-github/</guid><description>&lt;p&gt;この記事では、個人用と仕事用のGitHubアカウントを、プロジェクトディレクトリごとに自動的に切り替えて使用する方法を詳しく解説します。具体的には、&lt;code&gt;~/projects/personal&lt;/code&gt; ディレクトリ下のプロジェクトでは個人のGitHubアカウントを使用し、&lt;code&gt;~/projects/work&lt;/code&gt; ディレクトリ下では仕事用のアカウントを使用する状況を想定します。コマンドラインでのGit操作だけでなく、VSCodeなどのIDEでも適用されるようにします。&lt;/p&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;Gitの基本的な知識があること。&lt;/li&gt;&#10;&lt;li&gt;アカウントごとにSSHキーを生成しており、それぞれのGitHubアカウントに登録していること。&lt;/li&gt;&#10;&lt;li&gt;基本的なGit操作に慣れていること。&lt;/li&gt;&#10;&lt;li&gt;Git 2.13以降であること。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="git設定の基本"&gt;Git設定の基本&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;.gitconfig&lt;/code&gt;ファイルはGitの設定を管理するための中心的なファイルで、ユーザ名やメールアドレス、エイリアス、スクリプトの実行設定などを含みます。全体的なユーザー設定（グローバル設定）は通常、ユーザのホームディレクトリに位置する&lt;code&gt;.gitconfig&lt;/code&gt;ファイルに記述されます。&lt;/p&gt;&#10;&lt;h3 id="ディレクトリごとのgit設定"&gt;ディレクトリごとのGit設定&#10;&lt;/h3&gt;&lt;p&gt;Git 2.13以上では、&lt;code&gt;includeIf&lt;/code&gt;ディレクティブを使用して、特定のディレクトリに基づいてGit設定を動的に適用することができます。これを利用して、異なるプロジェクトディレクトリで異なるGitHubアカウントを使い分ける設定を行います。&lt;/p&gt;&#10;&lt;h4 id="基本的なgitconfig設定"&gt;基本的な&lt;code&gt;.gitconfig&lt;/code&gt;設定&#10;&lt;/h4&gt;&lt;p&gt;ホームディレクトリの&lt;code&gt;.gitconfig&lt;/code&gt;に以下の設定を追加します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[user]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name = default_name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; email = default_email@example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[includeIf &amp;#34;gitdir:~/projects/personal/&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; path = ~/.gitconfig-personal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[includeIf &amp;#34;gitdir:~/projects/work/&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; path = ~/.gitconfig-work&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="各ディレクトリ用のgitconfigファイル"&gt;各ディレクトリ用の&lt;code&gt;.gitconfig&lt;/code&gt;ファイル&#10;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;~/.gitconfig-personal&lt;/code&gt;ファイルには次のように記述します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[user]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name = personal_username&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; email = personal_email@example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[core]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sshCommand = &amp;#34;ssh -i ~/.ssh/id_rsa_personal -F /dev/null&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;~/.gitconfig-work&lt;/code&gt;ファイルには次のように記述します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[user]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name = work_username&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; email = work_email@example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[core]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sshCommand = &amp;#34;ssh -i ~/.ssh/id_rsa_work -F /dev/null&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;ディレクトリベースでGitHubアカウントを管理することで、複数のアカウントを効率的かつ安全に運用することが可能です。設定は初めに少し時間がかかりますが、一度設定してしまえば、その後は自動で適切なアカウントが使用されるため、非常に便利です。&lt;/p&gt;&#10;</description></item><item><title>カレントディレクトリ以下のすべてのpng,jpgをwebpに変換するシェルスクリプト</title><link>https://ai.hack-le.com/pngjpg-webp/</link><pubDate>Mon, 25 Mar 2024 16:23:39 +0900</pubDate><guid>https://ai.hack-le.com/pngjpg-webp/</guid><description>&lt;p&gt;&lt;strong&gt;この記事の目的は、シェルスクリプトでカレントディレクトリ以下にあるjpgやpngといった画像ファイルを、すべてwebpに変換する&lt;/strong&gt;ことです。サブディレクトリ内のデータも含みます。また、高速化のために並列処理をします。&lt;/p&gt;&#10;&lt;p&gt;実行環境&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Machine: M2 Pro Mac mini (2023)&lt;/li&gt;&#10;&lt;li&gt;macOS Sonoma 14.3.1&lt;/li&gt;&#10;&lt;li&gt;GNU bash 5.2.26&lt;/li&gt;&#10;&lt;li&gt;ImageMagick 7.1.1-29&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="スクリプトの提示"&gt;スクリプトの提示&#10;&lt;/h2&gt;&lt;p&gt;以下に、この自動化された並列処理を実行するためのbashスクリプトを示します。このスクリプトは、指定したディレクトリ以下の画像ファイル（PNG、JPG、JPEG）を検索し、それらをwebpフォーマットに変換後、元のファイルを削除します。変換プロセスは並列で実行されるため、作業の完了にかかる時間が大幅に短縮されます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;convert_image&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;img&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;basename &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; .&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;img&lt;/span&gt;&lt;span class="p"&gt;##*.&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dirname &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;new_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;.webp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; convert &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$new_path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; -f convert_image&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -type f &lt;span class="se"&gt;\(&lt;/span&gt; -iname &lt;span class="se"&gt;\*&lt;/span&gt;.png -o -iname &lt;span class="se"&gt;\*&lt;/span&gt;.jpg -o -iname &lt;span class="se"&gt;\*&lt;/span&gt;.jpeg &lt;span class="se"&gt;\)&lt;/span&gt; -print0 &lt;span class="p"&gt;|&lt;/span&gt; parallel -0 convert_image&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このスクリプトは、すべてのPNG、JPG、およびJPEGファイルを現在のディレクトリおよびそのサブディレクトリから検索し、それぞれをwebpフォーマットに変換した後、元のファイルを削除します。この自動化されたプロセスにより、手動で行う場合と比べて大幅な時間短縮が可能になります。&lt;/p&gt;&#10;&lt;h2 id="スクリプトの実行方法"&gt;スクリプトの実行方法&#10;&lt;/h2&gt;&lt;p&gt;このセクションでは、前述のbashスクリプトを実行するために必要な環境設定と、スクリプトの具体的な使用方法について詳しく説明します。スクリプトを効果的に活用するには、いくつかの前提条件を満たし、適切な手順で実行することが重要です。&lt;/p&gt;&#10;&lt;p&gt;前提条件は以下です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ImageMagickのインストール&lt;/strong&gt;: このスクリプトは&lt;code&gt;convert&lt;/code&gt;コマンドを使用して画像をwebpフォーマットに変換します。&lt;code&gt;convert&lt;/code&gt;コマンドは、ImageMagickソフトウェアスイートの一部です。ImageMagickは多くのLinuxディストリビューション、macOS、およびWindowsで利用可能です。お使いのシステムにImageMagickがインストールされていない場合は、公式の&lt;a class="link" href="https://imagemagick.org/script/download.php" target="_blank" rel="noopener"&#10; &gt;ImageMagickダウンロードページ&lt;/a&gt;からインストールすることができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;GNU parallelのインストール&lt;/strong&gt;: このスクリプトはGNU parallelを使用して、画像変換プロセスを並列で実行します。これにより、複数の画像を同時に処理することができ、全体の処理時間が大幅に短縮されます。GNU parallelはLinuxディストリビューションのパッケージマネージャーや&lt;a class="link" href="https://www.gnu.org/software/parallel/" target="_blank" rel="noopener"&#10; &gt;GNU parallelの公式ページ&lt;/a&gt;を通じてインストールできます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="スクリプトの主要部分解説"&gt;スクリプトの主要部分解説&#10;&lt;/h2&gt;&lt;p&gt;このセクションでは、先に紹介したbashスクリプトの構成要素を詳しく説明し、各部分がどのように機能するかを解説します。スクリプトは大きく分けて三つの主要な処理ステップによって構成されています。画像ファイルの検索、画像の並列変換、および元の画像ファイルの削除です。&lt;/p&gt;&#10;&lt;h3 id="1-画像ファイルの検索"&gt;1. 画像ファイルの検索&#10;&lt;/h3&gt;&lt;p&gt;スクリプトは&lt;code&gt;find&lt;/code&gt;コマンドを使用して、指定したディレクトリ以下のすべてのPNG、JPG、JPEGファイルを検索します。この検索は再帰的に行われ、サブディレクトリ内のファイルも対象となります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -type f &lt;span class="se"&gt;\(&lt;/span&gt; -iname &lt;span class="se"&gt;\*&lt;/span&gt;.png -o -iname &lt;span class="se"&gt;\*&lt;/span&gt;.jpg -o -iname &lt;span class="se"&gt;\*&lt;/span&gt;.jpeg &lt;span class="se"&gt;\)&lt;/span&gt; -print0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;.&lt;/code&gt;は現在のディレクトリを表します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-type f&lt;/code&gt;はファイルタイプが「ファイル」であるものを検索対象とします。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-iname&lt;/code&gt;は大文字小文字を区別せずに名前が一致するファイルを検索します。ここでは、&lt;code&gt;.png&lt;/code&gt;、&lt;code&gt;.jpg&lt;/code&gt;、&lt;code&gt;.jpeg&lt;/code&gt;の各拡張子を持つファイルを対象としています。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-print0&lt;/code&gt;は検索結果をNULL文字で区切って出力します。これは&lt;code&gt;parallel&lt;/code&gt;コマンドでの処理に必要です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-画像の並列変換"&gt;2. 画像の並列変換&#10;&lt;/h3&gt;&lt;p&gt;検索した画像ファイルは&lt;code&gt;parallel&lt;/code&gt;コマンドを通じて並列に処理されます。このステップでは、各画像ファイルがwebpフォーマットに変換されます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;parallel -0 convert_image&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-0&lt;/code&gt;オプションは、入力がNULL文字で区切られていることを&lt;code&gt;parallel&lt;/code&gt;に指示します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;convert_image&lt;/code&gt;は画像を変換するために定義された関数です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;GNU parallelは、複数のプロセスを並列で実行するための強力なツールです。このスクリプトでは、&lt;code&gt;parallel&lt;/code&gt;コマンドを用いて、検索された各画像ファイルに対して&lt;code&gt;convert_image&lt;/code&gt;関数を同時に実行させています。これにより、画像の変換タスクがCPUの複数のコアに分散され、タスクの完了速度が向上します。&lt;/p&gt;&#10;&lt;h3 id="3-画像変換関数-convert_image"&gt;3. 画像変換関数 &lt;code&gt;convert_image&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;この関数は、個々の画像ファイルをwebpフォーマットに変換し、成功したら元のファイルを削除します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;convert_image&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;img&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;basename &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; .&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;img&lt;/span&gt;&lt;span class="p"&gt;##*.&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dirname &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;new_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;.webp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; convert &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$new_path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;img=&amp;quot;$1&amp;quot;&lt;/code&gt;は関数に渡された最初の引数（ここでは画像ファイルのパス）を変数&lt;code&gt;img&lt;/code&gt;に代入します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;basename&lt;/code&gt;と&lt;code&gt;dirname&lt;/code&gt;コマンドを使用して、ファイル名（拡張子なし）とディレクトリのパスを取得します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;convert&lt;/code&gt;コマンドは画像をwebpフォーマットに変換します。変換が成功した場合（&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;の後）、&lt;code&gt;rm&lt;/code&gt;コマンドによって元のファイルが削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このスクリプトによって、大量の画像ファイルを効率的にwebpフォーマットに変換するプロセスが自動化されます。並列処理の採用により、この変換作業を大幅に高速化することができます。&lt;/p&gt;&#10;&lt;h2 id="トラブルシューティング"&gt;トラブルシューティング&#10;&lt;/h2&gt;&lt;p&gt;実際にスクリプトを使用する際には、いくつかの一般的な問題に遭遇する可能性があります。このセクションでは、最も一般的な問題とその解決策をいくつか紹介します。&lt;/p&gt;&#10;&lt;h3 id="1-gnu-parallelが見つからない"&gt;1. GNU parallelが見つからない&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;問題&lt;/strong&gt;: スクリプトを実行しようとすると、「parallel: command not found」というエラーメッセージが表示されます。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;解決策&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;GNU parallelがインストールされているかどうかを確認してください。インストールされていない場合は、お使いのシステムのパッケージマネージャーを使用してインストールします。例えば、Ubuntuでは&lt;code&gt;sudo apt-get install parallel&lt;/code&gt;を実行します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-imagemagickのconvertコマンドが機能しない"&gt;2. ImageMagickのconvertコマンドが機能しない&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;問題&lt;/strong&gt;: &lt;code&gt;convert&lt;/code&gt;コマンドを実行しようとするとエラーが発生するか、期待される出力が得られない。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;解決策&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ImageMagickが正しくインストールされているかを確認してください。インストールされていない、またはバージョンが古い場合は、最新版を公式ウェブサイトからダウンロードしてインストールします。&lt;/li&gt;&#10;&lt;li&gt;特にMac OSの場合、ImageMagickの最新バージョンでは&lt;code&gt;convert&lt;/code&gt;コマンドが&lt;code&gt;magick convert&lt;/code&gt;に置き換えられている可能性があります。その場合は、スクリプト内の&lt;code&gt;convert&lt;/code&gt;コマンドを&lt;code&gt;magick convert&lt;/code&gt;に変更してください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="3-スクリプトが特定の画像ファイルを見つけられない"&gt;3. スクリプトが特定の画像ファイルを見つけられない&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;問題&lt;/strong&gt;: スクリプトを実行しても、一部の画像ファイルが処理されない。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;解決策&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;find&lt;/code&gt;コマンドのパターンが正しいか確認してください。大文字小文字の違いが原因でファイルが見落とされることがあります。&lt;code&gt;-iname&lt;/code&gt;オプションは大文字小文字を区別しないため、これを使用していることを確認してください。&lt;/li&gt;&#10;&lt;li&gt;スクリプトが実行されているディレクトリと、処理したい画像ファイルが格納されているディレクトリが一致しているかを確認してください。必要に応じて、&lt;code&gt;find&lt;/code&gt;コマンドの検索パスを調整します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="参考資料"&gt;参考資料&#10;&lt;/h2&gt;&lt;p&gt;この記事では、大量の画像ファイルを効率的にwebp形式に変換し、そのプロセスを並列で実行するbashスクリプトの作成と使用について詳しく説明しました。このスクリプトを使用することで、画像処理タスクの時間を大幅に短縮し、ウェブサイトのパフォーマンスを向上させることができます。また、GNU parallelとImageMagickを活用することで、マルチコアプロセッサの能力を最大限に引き出し、作業の効率を向上させる方法も紹介しました。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://www.gnu.org/software/parallel/" target="_blank" rel="noopener"&#10; &gt;GNU Parallel Official Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://imagemagick.org/index.php" target="_blank" rel="noopener"&#10; &gt;ImageMagick Official Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Dockerの「Unused」と「Unused (dangling)」の理解</title><link>https://ai.hack-le.com/docker-unused-unused-dangling/</link><pubDate>Wed, 14 Feb 2024 12:21:24 +0900</pubDate><guid>https://ai.hack-le.com/docker-unused-unused-dangling/</guid><description>&lt;p&gt;Dockerを効果的に使用するには、そのリソース管理の仕組みを理解することが重要です。特に、多くの開発者が混乱することがあるのが、「Unused」と「Unused (dangling)」という用語の違いです。これらの状態を正確に理解し区別することは、不要なリソースを適切に管理し、システムのパフォーマンスを最適化するために必須です。&lt;/p&gt;&#10;&lt;p&gt;この記事の目的は、Dockerの「Unused」と「Unused (dangling)」の違いを明確にし、それぞれの実務的な影響を解析することです。さらに、プログラミングにおける「dangling」概念を掘り下げることで、コンピュータとソフトウェアの世界におけるこの重要な概念についての理解を深め、読者がより洗練されたソフトウェア開発者になる手助けをします。&lt;/p&gt;&#10;&lt;h2 id="dockerとは"&gt;Dockerとは&#10;&lt;/h2&gt;&lt;p&gt;Dockerは、ソフトウェアの開発、配布、実行を容易にするためのオープンソースプラットフォームです。この技術は、コンテナと呼ばれる軽量の実行環境を提供し、アプリケーションとその依存関係をパッケージ化して、環境間で一貫した動作を保証します。Dockerコンテナは、仮想マシンに似ていますが、より軽量で、より速く起動し、システムリソースをより少なく消費します。これにより、開発者はアプリケーションを迅速に開発、テスト、デプロイすることができます。&lt;/p&gt;&#10;&lt;h3 id="コンテナ技術の概要"&gt;コンテナ技術の概要&#10;&lt;/h3&gt;&lt;p&gt;コンテナ技術は、アプリケーションとそのランタイム環境をカプセル化し、異なるコンピューティング環境間でアプリケーションを簡単に移動できるようにする技術です。このカプセル化により、開発者は「それは私のマシン上では動作する」という問題を避けることができ、生産性の向上につながります。コンテナは、アプリケーションの実行に必要なコード、ランタイム、システムツール、ライブラリ、設定を含んでいます。&lt;/p&gt;&#10;&lt;h3 id="dockerの利点"&gt;Dockerの利点&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ポータビリティ&lt;/strong&gt;: Dockerコンテナは、どのDocker環境でも同じように動作します。これにより、開発からテスト、本番環境への移行がスムーズになります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;効率&lt;/strong&gt;: コンテナは、仮想マシンよりもはるかに軽量で、リソース消費が少なく、起動が速いです。これにより、同じハードウェア上でより多くのアプリケーションを実行することが可能になります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;分離&lt;/strong&gt;: 各コンテナは他から独立して実行され、プロセスやファイルシステムが隔離されているため、セキュリティが向上します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;スケーラビリティと管理の容易さ&lt;/strong&gt;: Dockerを使用すると、コンテナを簡単にスケーリングし、複数のインスタンスを効率的に管理できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Dockerのこれらの利点は、開発者がアプリケーションの開発に集中できるようにするだけでなく、運用チームがアプリケーションのデプロイメントと管理をより効率的に行うことを可能にします。次のセクションでは、Dockerのリソース管理、特に「Unused」と「Unused (dangling)」リソースの扱いに焦点を当て、これらの違いと実務上の意味について詳しく見ていきます。&lt;/p&gt;&#10;&lt;h2 id="dockerのunusedとunused-danglingの違い"&gt;Dockerの「Unused」と「Unused (dangling)」の違い&#10;&lt;/h2&gt;&lt;p&gt;Dockerを使用する際に避けて通れないのが、リソースの効率的な管理です。特に、「Unused」と「Unused (dangling)」という用語は、リソース管理において重要な役割を果たします。これらの状態を理解し、適切に扱うことは、システムのパフォーマンスを最適化し、ディスクスペースを有効に利用するために不可欠です。&lt;/p&gt;&#10;&lt;h3 id="unusedリソースとは"&gt;Unusedリソースとは&#10;&lt;/h3&gt;&lt;p&gt;「Unused」とは、現在アクティブなコンテナによって使用されていないDockerリソースを指します。これには、コンテナ、イメージ、ボリューム、ネットワークが含まれますが、これらは将来的に再利用する可能性があるため、自動的には削除されません。たとえば、あるイメージからコンテナを生成していない場合、そのイメージは「Unused」と見なされますが、後にそのイメージを基に新たなコンテナを作成することができます。&lt;/p&gt;&#10;&lt;h3 id="unused-danglingリソースとは"&gt;Unused (dangling)リソースとは&#10;&lt;/h3&gt;&lt;p&gt;「Unused (dangling)」リソースは、特にイメージに関してよく使われる用語で、タグがない、または特定のコンテナやイメージから参照されていないイメージのことを指します。これは通常、新しいイメージをビルドした際に古いイメージが置き換えられ、その古いイメージがタグから外れた結果生じます。danglingイメージは、不要なディスクスペースを占有しており、システムの整理やパフォーマンス向上のために定期的に削除することが推奨されます。&lt;/p&gt;&#10;&lt;h3 id="実務上の違い"&gt;実務上の違い&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;管理の必要性&lt;/strong&gt;: Unusedリソースは、将来的に使用する可能性があるため、管理者が削除を決定する必要があります。一方で、Unused (dangling)リソースは通常、再利用の価値がなく、ディスクスペースを不必要に消費するため、定期的なクリーンアップが推奨されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;クリーンアップ方法&lt;/strong&gt;: Dockerは、これらのリソースをクリーンアップするためにいくつかのコマンドを提供しています。&lt;code&gt;docker system prune&lt;/code&gt;コマンドは、未使用のリソースを一括で削除しますが、&lt;code&gt;docker image prune&lt;/code&gt;コマンドは特にUnused (dangling)イメージの削除に使用されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このセクションを通じて、Dockerのリソース管理における「Unused」と「Unused (dangling)」の違いと、それらを適切に管理することの重要性を理解することができました。次に、具体的なリソース管理のコマンドとベストプラクティスについて詳しく見ていきましょう。&lt;/p&gt;&#10;&lt;h2 id="dockerでのリソース管理"&gt;Dockerでのリソース管理&#10;&lt;/h2&gt;&lt;p&gt;Dockerの効率的な運用において、不要なリソースのクリーンアップはシステムのパフォーマンスを維持し、ディスクスペースを節約するために欠かせません。Dockerは、これらのリソースを効率的に管理し、クリーンアップするための複数のコマンドを提供しています。主に&lt;code&gt;docker system prune&lt;/code&gt;と&lt;code&gt;docker image prune&lt;/code&gt;の二つのコマンドが使われますが、それぞれの使用法と違いを理解することが重要です。&lt;/p&gt;&#10;&lt;h3 id="docker-system-prune-コマンド"&gt;&lt;code&gt;docker system prune&lt;/code&gt; コマンド&#10;&lt;/h3&gt;&lt;p&gt;このコマンドは、システム上の未使用のDockerリソース全体をクリーンアップするために使用されます。具体的には、未使用のコンテナ、ネットワーク、イメージ（未使用とdanglingの両方）、およびビルドキャッシュを削除します。このコマンドは特に、ディスクスペースを効率的に解放したい場合に有用です。&lt;/p&gt;&#10;&lt;p&gt;使用法の例:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker system prune&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="docker-image-prune-コマンド"&gt;&lt;code&gt;docker image prune&lt;/code&gt; コマンド&#10;&lt;/h3&gt;&lt;p&gt;このコマンドは、特にUnused (dangling)イメージの削除に焦点を当てています。danglingイメージは、タグから外れ、どのコンテナからも参照されていないイメージであり、これらを定期的にクリーンアップすることで、ディスクスペースを節約することができます。&lt;/p&gt;&#10;&lt;p&gt;使用法の例:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker image prune&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを実行すると、ユーザーに確認なしにdanglingイメージが削除されます。さらに詳細な制御を求める場合は、&lt;code&gt;-a&lt;/code&gt;オプションを使用して、未使用のイメージ（danglingだけでなく、未使用のイメージも含む）を削除することもできます。&lt;/p&gt;&#10;&lt;h3 id="ベストプラクティス"&gt;ベストプラクティス&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;定期的なクリーンアップ&lt;/strong&gt;: システムのパフォーマンスとディスクスペースの最適化を保つために、定期的に&lt;code&gt;docker system prune&lt;/code&gt;および&lt;code&gt;docker image prune&lt;/code&gt;コマンドを使用してクリーンアップを行うことが推奨されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;確認とバックアップ&lt;/strong&gt;: 重要なデータやイメージが失われないように、削除を実行する前に、影響を受けるリソースを確認し、必要に応じてバックアップを取ることが重要です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;リソースの使用状況の監視&lt;/strong&gt;: 不要なリソースが蓄積しないように、定期的にDockerのリソース使用状況を監視することも良い習慣です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Dockerでのリソース管理は、システムの健全性と効率性を維持するために重要です。適切なコマンドの使用と定期的なクリーンアップにより、Docker環境を最適な状態に保つことができます。&lt;/p&gt;&#10;&lt;h2 id="プログラミングにおけるdangling概念の掘り下げ"&gt;プログラミングにおける「Dangling」概念の掘り下げ&#10;&lt;/h2&gt;&lt;p&gt;「Dangling」という用語は、Dockerのコンテキストを超えて、プログラミング全般においても重要な概念です。特に、メモリ管理やリソースの参照を扱う際には、この概念の理解が必須となります。ここでは、「Dangling Pointer」と「Dangling Reference」という二つの一般的なシナリオを掘り下げてみましょう。&lt;/p&gt;&#10;&lt;h3 id="dangling-pointer"&gt;Dangling Pointer&#10;&lt;/h3&gt;&lt;p&gt;「Dangling Pointer」とは、解放されたメモリ領域を指しているポインタのことを指します。メモリが解放されると、そのアドレスに対するポインタは有効なデータを指していない状態になりますが、プログラムが誤ってそのポインタを通じてアクセスしようとすると、未定義の動作が発生します。これは、メモリの安全性やデータの整合性にとって重大なリスクをもたらします。&lt;/p&gt;&#10;&lt;h3 id="dangling-reference"&gt;Dangling Reference&#10;&lt;/h3&gt;&lt;p&gt;「Dangling Reference」とは、そのライフタイムが終了し、もはや有効でないオブジェクトを参照している変数のことを指します。これは、主に高レベル言語において見られる問題で、ポインタと同様に、参照が無効なオブジェクトを指している状態を指します。無効な参照を通じてオブジェクトにアクセスしようとすると、プログラムのクラッシュや予期しない動作の原因となります。&lt;/p&gt;&#10;&lt;h3 id="なぜdangling概念を理解することが重要か"&gt;なぜ「Dangling」概念を理解することが重要か&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティ&lt;/strong&gt;: Dangling PointerやReferenceは、プログラムのセキュリティ上の脆弱性を引き起こす可能性があります。攻撃者はこれらを利用して、メモリ破壊や機密情報の漏洩を試みることがあります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;安定性&lt;/strong&gt;: プログラムの安定性を確保するためには、dangling状態を避け、リソースが適切に管理されていることを保証する必要があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;パフォーマンス&lt;/strong&gt;: 不要なリソースがシステム上に残り続けると、パフォーマンスに影響を及ぼす可能性があります。適切なクリーンアップにより、リソースの使用効率を最適化することができます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;プログラミングにおいて「Dangling」概念を理解することは、効率的で安全なコードを書くために不可欠です。特に、システムプログラミングや低レベルの言語を使用する場合には、メモリ管理やリソースの参照に特別な注意を払う必要があります。高レベル言語やクラウドベースの開発では、これらの問題が自動的に管理されることが多いですが、背後で何が起こっているのかを理解することは、開発者としてのスキルを深める上で非常に価値があります。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;本記事を通じて、Dockerの「Unused」と「Unused (dangling)」リソースの違いとその重要性について解説しました。また、プログラミング全般にわたる「Dangling」概念の理解が、エラーの予防、セキュリティの向上、システムの安定性保持、パフォーマンスの最適化にどのように寄与するかについて掘り下げました。これらの知識は、効率的で安全なソフトウェア開発を実現するための基礎を形成します。&lt;/p&gt;&#10;&lt;h3 id="dockerリソース管理の重要性"&gt;Dockerリソース管理の重要性&#10;&lt;/h3&gt;&lt;p&gt;Dockerの効果的な利用には、リソース管理の適切な理解と実践が不可欠です。未使用のリソースを適時にクリーンアップすることで、システムのパフォーマンスを維持し、ディスクスペースを有効に活用することが可能です。&lt;code&gt;docker system prune&lt;/code&gt;や&lt;code&gt;docker image prune&lt;/code&gt;などのコマンドを適切に使用することで、Docker環境を整理し、管理することが重要です。&lt;/p&gt;&#10;&lt;h3 id="プログラミングにおけるdangling概念の普遍性"&gt;プログラミングにおける「Dangling」概念の普遍性&#10;&lt;/h3&gt;&lt;p&gt;「Dangling」は、Dockerだけでなく、プログラミングの多くの側面で見られる概念です。メモリ管理、リソースの参照、そして安全なコードの記述において、この概念を理解し適切に対処することは、ソフトウェアの品質を決定づける要因となります。プログラマとして、これらの基本的な概念を理解し、実践することは、プロフェッショナルなスキルセットを構築する上で欠かせません。&lt;/p&gt;&#10;&lt;h3 id="継続的な学習の重要性"&gt;継続的な学習の重要性&#10;&lt;/h3&gt;&lt;p&gt;技術は日々進化しており、新しいツールや概念が常に登場しています。Dockerやプログラミングの基礎概念について学ぶことは、変化する技術環境に適応し、成長し続けるための第一歩です。継続的な学習と実践を通じて、これらの知識を深め、応用することが、効果的なソフトウェア開発者になるための鍵です。&lt;/p&gt;&#10;&lt;p&gt;最終的に、Dockerのリソース管理とプログラミングにおける「Dangling」概念の理解は、ソフトウェア開発の質を向上させるための基本的なステップです。これらの概念を適切に理解し活用することで、より効率的で安全、かつ信頼性の高いアプリケーションを構築することが可能になります。&lt;/p&gt;&#10;</description></item><item><title>Amazon Cognitoの認証フロー解説</title><link>https://ai.hack-le.com/amazon-cognito-auth-flow/</link><pubDate>Mon, 08 Jan 2024 19:19:37 +0900</pubDate><guid>https://ai.hack-le.com/amazon-cognito-auth-flow/</guid><description>&lt;p&gt;この記事は、Cognitoの認証フローの各選択肢について解説します。また、なぜ多くのアプリケーションにおいて&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローだけで十分であるのか、その理由を明確に説明することを目指します。&lt;/p&gt;&#10;&lt;h2 id="cognitoでの認証フローの種類"&gt;Cognitoでの認証フローの種類&#10;&lt;/h2&gt;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2024/01/1c1d29ba627cf54364d14c71b6218125.png"&gt;&lt;/p&gt;&#10;&lt;p&gt;Amazon Cognitoは、セキュアなユーザー管理と認証フローを実現するための多様なオプションを提供します。これにより、開発者はアプリケーションのセキュリティ要件に応じて最適な認証戦略を選択できます。Cognitoが提供する認証フローは、以下のように分類されます。&lt;/p&gt;&#10;&lt;h3 id="adminユーザーによる認証allow_admin_user_password_auth"&gt;ADMINユーザーによる認証（ALLOW_ADMIN_USER_PASSWORD_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;この認証フローは、アプリケーションのバックエンドや管理者がユーザーの代わりに認証を行う場合に使用されます。例えば、新規ユーザーのアカウントをセットアップする際や、パスワードリセットのプロセス中に管理者が介入する必要がある場合などです。このフローは強力で柔軟性がありますが、管理者の権限を使うため、セキュリティ対策を十分に施す必要があります。&lt;/p&gt;&#10;&lt;h3 id="カスタム認証allow_custom_auth"&gt;カスタム認証（ALLOW_CUSTOM_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;カスタム認証フローは、開発者が独自の認証シーケンスを実装したい場合に適しています。AWS Lambdaトリガーを活用して、ワンタイムパスワードやキャプチャ、二要素認証など、標準的なユーザー名とパスワードの組み合わせ以外の方法でユーザーを認証するロジックをカスタマイズできます。これは、特定のセキュリティ要件を満たすためや、ユーザーエクスペリエンスを向上させるために有効です。&lt;/p&gt;&#10;&lt;h3 id="ユーザーによるパスワード認証allow_user_password_auth"&gt;ユーザーによるパスワード認証（ALLOW_USER_PASSWORD_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;ユーザーによるパスワード認証フローは、ユーザーが直接自身のユーザー名とパスワードを提供してサインインする一般的な認証方法です。このフローはシンプルで直感的なため、ユーザーには親しみやすいですが、パスワードが直接送信されるため、SRPを使用するフローと比較してセキュリティ上のリスクが高くなります。&lt;/p&gt;&#10;&lt;h3 id="srpによるユーザー認証allow_user_srp_auth"&gt;SRPによるユーザー認証（ALLOW_USER_SRP_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;SRPによるユーザー認証フローは、ユーザー名とパスワードを使用しながらも、パスワードをネットワーク上で送信せずに認証する方法です。これは、セキュリティを強化しつつ、ユーザーが簡単にサインインできる方法を提供します。SRPプロトコルは、数学的な計算に基づいており、パスワードの代わりに一時的な証明を交換することで認証を行います。これにより、万が一通信が盗聴されても、パスワードが漏洩するリスクが非常に低くなります。&lt;/p&gt;&#10;&lt;h3 id="リフレッシュトークンによる認証allow_refresh_token_auth"&gt;リフレッシュトークンによる認証（ALLOW_REFRESH_TOKEN_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;ユーザーが一度サインインすると、リフレッシュトークンを使用してセッションを維持し、新しいアクセストークンやIDトークンを定期的に取得できます。これは、長期間にわたるセッション管理に適しており、ユーザーが頻繁にサインインし直す必要をなくします。&lt;/p&gt;&#10;&lt;p&gt;これらの認証フローは、アプリケーションのニーズに合わせて柔軟に組み合わせることができますが、多くのシナリオでは&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローだけでセキュリティと利便性のバランスを取ることが可能です。次のセクションでは、このフローがなぜ多くの場合で最適な選択であるかについて、さらに深堀りしていきます。&lt;/p&gt;&#10;&lt;h2 id="allow_user_srp_authの重要性"&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;の重要性&#10;&lt;/h2&gt;&lt;p&gt;セキュアな認証フローを実現するためには、ユーザーの資格情報が安全であることを確保しなければなりません。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;は、この目的を達成するための最も効果的な手段の一つです。このフローはセキュアリモートパスワード（SRP）プロトコルを使用し、パスワードを直接ネットワーク上で交換することなく、サーバーがユーザーの身元を検証することを可能にします。結果として、セキュリティが大幅に向上し、潜在的な攻撃からユーザーのパスワードを保護します。&lt;/p&gt;&#10;&lt;h3 id="パスワード露出のリスク回避"&gt;パスワード露出のリスク回避&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_PASSWORD_AUTH&lt;/code&gt;フローでは、ユーザーのパスワードがクライアントからサーバーへと明示的に送信されます。これは、中間者攻撃や、ネットワーク上でのデータの盗聴といったセキュリティの脅威に対して脆弱性を持ちます。対照的に、&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローでは、パスワードに代わる一時的な証明が生成され、この証明だけが交換されます。そのため、ユーザーの実際のパスワードはサーバーや他のどのネットワーク機器にも露出することはありません。&lt;/p&gt;&#10;&lt;h3 id="セキュリティとユーザビリティのバランス"&gt;セキュリティとユーザビリティのバランス&#10;&lt;/h3&gt;&lt;p&gt;セキュリティ対策は、ユーザビリティを損なわないように慎重に行われるべきです。ユーザーにとって複雑すぎる認証プロセスは、使い勝手を低下させる原因となります。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、高いセキュリティを維持しつつも、エンドユーザーには通常のユーザー名とパスワードを入力するだけの簡単な手順を提供します。これにより、最終的なユーザーエクスペリエンスは向上し、セキュリティに関する知識がないユーザーでも安全にサービスを利用できます。&lt;/p&gt;&#10;&lt;h3 id="クライアントアプリケーションとの互換性"&gt;クライアントアプリケーションとの互換性&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、多くのクライアントライブラリやフレームワークでサポートされており、開発者は追加の労力をかけずにこの認証フローを実装できます。AWSのSDKなどのツールは、このプロトコルを直接扱うことができるため、開発者はセキュリティの複雑さを理解しなくても、安全な認証システムを構築できます。&lt;/p&gt;&#10;&lt;p&gt;総合すると、&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、高いセキュリティ基準と優れたユーザーエクスペリエンスの両方を提供します。クライアントアプリケーションにとって、このフローはセキュアな認証プロセスを簡単に実装するための鍵となるため、多くの一般的な使用シナリオで推奨される選択肢です。多くの一般的なクライアントアプリケーションでは、&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;認証フローだけでユーザー認証の要件を満たすことができます。&lt;/p&gt;&#10;&lt;p&gt;セキュリティのベストプラクティスとして、最小限の必要権限でシステムを運用することが推奨されます。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;はこの原則に沿っており、最小限の認証情報のみを使用して最大限のセキュリティを提供します。これにより、不要なセキュリティリスクを排除し、アプリケーションの攻撃面を最小限に抑えることができます。&lt;/p&gt;&#10;&lt;h2 id="認証フローの実装ガイド"&gt;認証フローの実装ガイド&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt; フローを利用した実装は、セキュリティを重視しながらもユーザーフレンドリーなアプリケーションを構築する上で重要です。このセクションでは、具体的な実装ステップとベストプラクティスを提供します。&lt;/p&gt;&#10;&lt;h3 id="実装の前提条件と準備"&gt;実装の前提条件と準備&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt; フローを実装する前に、以下の前提条件と準備が必要です：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Cognito User Poolの設定&lt;/strong&gt;: AWS Cognito User Poolを設定し、アプリケーションクライアントIDを取得します。これは、ユーザー認証時にCognitoとの通信に使用されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;適切なAWS SDKの選択&lt;/strong&gt;: AWS SDK（たとえば、AWS SDK for JavaScript、Boto3 for Pythonなど）を選択し、プロジェクトに組み込みます。これらのSDKは、SRP認証フローをサポートしており、実装を容易にします。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティの構成&lt;/strong&gt;: HTTPS通信を確保し、エンドポイントのセキュリティを強化します。これにより、データのプライバシーと完全性が保たれます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="allow_user_srp_authを使用した認証プロセスのコード例"&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;を使用した認証プロセスのコード例&#10;&lt;/h3&gt;&lt;p&gt;以下に、JavaScriptを使用したAWS CognitoとのSRP認証プロセスの基本的なコード例を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;amazon-cognito-identity-js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;aws-sdk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;poolData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;UserPoolId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ap-northeast-1_Example&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Cognito User Pool ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ClientId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;exampleclientid&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;// Cognito User Pool Client ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CognitoUserPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;poolData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticationData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticationDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AuthenticationDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticationData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userPool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cognitoUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CognitoUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;cognitoUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticationDetails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;onSuccess&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Authentication successful!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;onFailure&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Authentication failed:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、ユーザーがユーザー名とパスワードを提供してサインインする基本的なシナリオを実装しています。成功時にはセッション情報が取得され、失敗時にはエラーが報告されます。&lt;/p&gt;&#10;&lt;h3 id="ベストプラクティスとデバッグのヒント"&gt;ベストプラクティスとデバッグのヒント&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;エラーハンドリングの実装&lt;/strong&gt;: 認証プロセス中に発生する可能性のあるエラーを適切に処理し、ユーザーにわかりやすいフィードバックを提供します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティの監査とテスト&lt;/strong&gt;: アプリケーションのセキュリティを定期的に監査し、脆弱性テストを実施して、セキュリティの弱点を特定し対処します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ログの活用&lt;/strong&gt;: 認証プロセスにおける詳細なログを記録し、問題発生時の迅速なトラブルシューティングに役立てます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt; フローの実装は、セキュアなユーザー認証を提供するための基礎を形成します。このフローを適切に利用することで、ユーザーの安全を保ちながら、優れたユーザーエクスペリエンスを提供するアプリケーションを構築できます。次のセクションでは、これまでの内容をまとめ、認証フローの選択がアプリケーションに与える影響について総括します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事では、Amazon Cognitoの認証フローについて深く掘り下げ、特に&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローが多くのアプリケーションにとってなぜ最適な選択肢であるかを詳細に説明しました。このフローは、セキュリティとユーザビリティのバランスを最適化し、開発者にとっても容易に実装可能な選択肢です。&lt;/p&gt;&#10;&lt;h3 id="認証フロー選択の意思決定プロセス"&gt;認証フロー選択の意思決定プロセス&#10;&lt;/h3&gt;&lt;p&gt;認証フローの選択は、アプリケーションのセキュリティ要件、ユーザーエクスペリエンス、開発の容易さを考慮して行うべきです。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;は、これらの要素をバランス良く兼ね備えているため、一般的なアプリケーション開発において最適な選択となることが多いです。ただし、特定のケースでは他の認証フローやカスタム認証が必要になることもあります。&lt;/p&gt;&#10;&lt;h3 id="セキュリティを維持しながらのユーザーエクスペリエンスの最適化"&gt;セキュリティを維持しながらのユーザーエクスペリエンスの最適化&#10;&lt;/h3&gt;&lt;p&gt;ユーザーが直感的に利用できる安全な認証システムは、アプリケーションの成功において重要な要素です。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、ユーザーに対して簡単かつ安全なサインインプロセスを提供し、同時にデータ保護の最高基準を満たします。&lt;/p&gt;&#10;&lt;h3 id="認証フローの今後の展望"&gt;認証フローの今後の展望&#10;&lt;/h3&gt;&lt;p&gt;セキュリティ技術の進化に伴い、認証フローの選択肢も変化していきます。Cognitoのようなサービスは継続的にアップデートされ、新しいセキュリティ機能やユーザビリティ向上のためのオプションが提供されることが予想されます。そのため、開発者は常に最新のセキュリティトレンドとベストプラクティスに注意を払い、アプリケーションのセキュリティを維持する必要があります。&lt;/p&gt;&#10;&lt;p&gt;認証フローの選択は、アプリケーションのセキュリティとユーザーエクスペリエンスに大きな影響を与えます。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは多くの場合に最適な選択ですが、プロジェクトの特定の要件に基づいて最終的な決定を行うことが重要です。この記事が、Cognitoの認証フローに関する理解を深め、適切な選択を行うためのガイドとなれば幸いです。&lt;/p&gt;&#10;</description></item><item><title>カレントディレクトリの.rarファイルを展開する(Bash, Fish)</title><link>https://ai.hack-le.com/%E3%82%AB%E3%83%AC%E3%83%B3%E3%83%88%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AE-rar%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%B1%95%E9%96%8B%E3%81%99%E3%82%8Bbash-fish/</link><pubDate>Wed, 03 Jan 2024 09:21:21 +0900</pubDate><guid>https://ai.hack-le.com/%E3%82%AB%E3%83%AC%E3%83%B3%E3%83%88%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AE-rar%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%B1%95%E9%96%8B%E3%81%99%E3%82%8Bbash-fish/</guid><description>&lt;p&gt;&lt;code&gt;.rar&lt;/code&gt; ファイルを Bash や Fish シェルで展開するためには、&lt;code&gt;unrar&lt;/code&gt; または &lt;code&gt;rar&lt;/code&gt; コマンドを使用します。これらのコマンドは &lt;code&gt;.rar&lt;/code&gt; 形式のファイルを処理するための標準的なツールです。まず、これらのコマンドがシステムにインストールされているか確認し、インストールされていなければ適切な手順でインストールしてください。&lt;/p&gt;&#10;&lt;h3 id="bash-での-rar-ファイルの展開"&gt;Bash での .rar ファイルの展開&#10;&lt;/h3&gt;&lt;p&gt;Bash シェルを使用して &lt;code&gt;.rar&lt;/code&gt; ファイルを展開するには、以下のコマンドを実行します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for file in *.rar; do unrar x &amp;#34;$file&amp;#34;; done&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、カレントディレクトリに存在する全ての &lt;code&gt;.rar&lt;/code&gt; ファイルを検索し、&lt;code&gt;unrar x&lt;/code&gt; コマンドを使ってそれぞれを展開します。&lt;/p&gt;&#10;&lt;h3 id="fish-での-rar-ファイルの展開"&gt;Fish での .rar ファイルの展開&#10;&lt;/h3&gt;&lt;p&gt;Fish シェルで &lt;code&gt;.rar&lt;/code&gt; ファイルを展開する場合、コマンドは少し異なりますが、基本的なプロセスは同じです。以下が Fish でのコマンドです：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for file in *.rar; unrar x $file; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドも、カレントディレクトリの全ての &lt;code&gt;.rar&lt;/code&gt; ファイルに対して &lt;code&gt;unrar&lt;/code&gt; コマンドを実行します。&lt;/p&gt;&#10;&lt;h3 id="注意点"&gt;注意点&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;unrar&lt;/code&gt; コマンドがシステムにインストールされている必要があります。Linux や Unix 系の OS では、パッケージマネージャを通じてインストールできます。例えば、Debian 系のディストリビューションでは &lt;code&gt;sudo apt-get install unrar&lt;/code&gt; コマンドでインストールできます。&lt;/li&gt;&#10;&lt;li&gt;Macの場合は &lt;a class="link" href="https://qiita.com/wm-ytakano/items/ec03961978f5578906a2" target="_blank" rel="noopener"&#10; &gt;MacでRARファイルをコマンドラインで解凍する(unrar) #Mac - Qiita&lt;/a&gt; より &lt;code&gt;$ brew install carlocab/personal/unrar&lt;/code&gt;でインストールできます。&lt;/li&gt;&#10;&lt;li&gt;展開したいファイルが保存されているディレクトリに移動してからコマンドを実行してください。&lt;/li&gt;&#10;&lt;li&gt;ファイル名にスペースや特殊文字が含まれている場合は、ファイル名をダブルクォートで囲むことで、正しく処理されるようにしてください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>カレントディレクトリの.lzhファイルをBashとFishで展開する方法</title><link>https://ai.hack-le.com/lzh-bash-fish/</link><pubDate>Wed, 03 Jan 2024 09:01:58 +0900</pubDate><guid>https://ai.hack-le.com/lzh-bash-fish/</guid><description>&lt;p&gt;コンピュータを使った作業では、様々なファイルを扱いますが、特にアーカイブファイルはその中でも重要な役割を果たしています。アーカイブファイルには多くの種類がありますが、今回は&lt;code&gt;.lzh&lt;/code&gt;形式のファイルに注目します。&lt;code&gt;.lzh&lt;/code&gt;はかつて日本で広く使われていた圧縮形式で、今でも歴史的なデータや特定のコンテンツを扱う際に見かけることがあります。&lt;/p&gt;&#10;&lt;p&gt;このブログ記事では、&lt;code&gt;.lzh&lt;/code&gt;ファイルを効率的に展開する方法を、BashとFishという二つの異なるシェルを使って紹介します。BashはLinuxやUnix系のオペレーティングシステムで最も一般的に使われるシェルで、その強力なスクリプト機能は多くのユーザーに愛されています。一方で、Fishはより最近のシェルで、そのユーザーフレンドリーな設計と直感的な構文が特徴です。&lt;/p&gt;&#10;&lt;h2 id="bashでのlzhファイルの展開"&gt;Bashでの.lzhファイルの展開&#10;&lt;/h2&gt;&lt;p&gt;Bashシェルは、LinuxやUnix系のオペレーティングシステムで広く採用されているコマンドラインインターフェースです。その強力なスクリプティング機能と柔軟性により、多くの開発者やシステム管理者にとって欠かせないツールとなっています。ここでは、Bashを使用して&lt;code&gt;.lzh&lt;/code&gt;ファイルを効率的に展開する方法を紹介します。&lt;/p&gt;&#10;&lt;p&gt;まず、&lt;code&gt;.lzh&lt;/code&gt;ファイルの展開には&lt;code&gt;lha&lt;/code&gt;コマンドが必要です。このコマンドは多くのLinuxディストリビューションやUnix系OSで利用可能ですが、インストールされていない場合は、パッケージマネージャを通じてインストールする必要があります。例えば、Debian系のLinuxディストリビューションでは、次のコマンドで&lt;code&gt;lha&lt;/code&gt;をインストールできます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install lha&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;インストールが完了したら、カレントディレクトリにあるすべての&lt;code&gt;.lzh&lt;/code&gt;ファイルを展開するためのコマンドを実行します。以下がそのコマンドです：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.lzh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; lha x &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、カレントディレクトリに存在するすべての&lt;code&gt;.lzh&lt;/code&gt;ファイルに対して、ループを用いて一つずつ&lt;code&gt;lha x&lt;/code&gt;コマンドを実行します。&lt;code&gt;for&lt;/code&gt;ループの中で、&lt;code&gt;*.lzh&lt;/code&gt;はカレントディレクトリ内の全ての&lt;code&gt;.lzh&lt;/code&gt;ファイルにマッチします。各ファイル名は&lt;code&gt;file&lt;/code&gt;変数に格納され、&lt;code&gt;lha x &amp;quot;$file&amp;quot;&lt;/code&gt;コマンドによってそれぞれのファイルが展開されます。ダブルクォーテーションは、ファイル名にスペースや特殊文字が含まれている場合に備えて、ファイル名を正しく処理するために使用します。&lt;/p&gt;&#10;&lt;h2 id="fishでのlzhファイルの展開"&gt;Fishでの.lzhファイルの展開&#10;&lt;/h2&gt;&lt;p&gt;Fishシェルは、使いやすさと直感的な機能を重視した近代的なコマンドラインシェルです。Bashと比較して、より洗練されたユーザーインターフェースとシンプルな構文を提供しています。ここでは、Fishを使用して&lt;code&gt;.lzh&lt;/code&gt;ファイルを効率的に展開する方法を紹介します。&lt;/p&gt;&#10;&lt;p&gt;Bashと同様に、Fishでの展開にも&lt;code&gt;lha&lt;/code&gt;コマンドが必要です。&lt;code&gt;lha&lt;/code&gt;がまだインストールされていない場合は、システムのパッケージマネージャを使ってインストールしてください。インストールが完了したら、以下のコマンドを実行して、カレントディレクトリにある全ての&lt;code&gt;.lzh&lt;/code&gt;ファイルを展開します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.lzh&lt;span class="p"&gt;;&lt;/span&gt; lha x &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、カレントディレクトリ内の全ての&lt;code&gt;.lzh&lt;/code&gt;ファイルに対して&lt;code&gt;lha&lt;/code&gt;コマンドを使用します。&lt;code&gt;for&lt;/code&gt;ループは、指定されたパターンにマッチする各ファイルに対してコマンドを実行します。ここでの&lt;code&gt;*.lzh&lt;/code&gt;は、カレントディレクトリの全ての&lt;code&gt;.lzh&lt;/code&gt;ファイルを指します。&lt;code&gt;lha x $file&lt;/code&gt;コマンドはそれぞれのファイルを展開し、&lt;code&gt;end&lt;/code&gt;キーワードでループが終了します。&lt;/p&gt;&#10;&lt;p&gt;Fishシェルの特徴の一つは、その構文の簡潔さです。Bashに比べてコマンドが短く、読みやすいため、シェルスクリプティングの初心者にも理解しやすいかもしれません。また、Fishには、コマンドの自動補完やシンタックスハイライトなどの便利な機能が標準で備わっており、日々の作業をより効率的にします。&lt;/p&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;.lzh&lt;/code&gt; ファイルを Bash や Fish で展開する際には、いくつかの重要な注意点があります。これらを理解し、適切に対処することで、ファイルの展開をスムーズかつ安全に行うことができます。&lt;/p&gt;&#10;&lt;h3 id="lha-コマンドのインストールと確認"&gt;&lt;code&gt;lha&lt;/code&gt; コマンドのインストールと確認&#10;&lt;/h3&gt;&lt;p&gt;最初に、&lt;code&gt;.lzh&lt;/code&gt; ファイルを扱うためには &lt;code&gt;lha&lt;/code&gt; コマンドが必須です。このコマンドはすべてのシステムに標準でインストールされているわけではありません。自分のシステムに &lt;code&gt;lha&lt;/code&gt; がインストールされているかを確認し、なければ適切なパッケージマネージャ（例えば、Linux の場合は &lt;code&gt;apt&lt;/code&gt; や &lt;code&gt;yum&lt;/code&gt;）を使用してインストールしてください。&lt;/p&gt;&#10;&lt;h3 id="ディレクトリの確認"&gt;ディレクトリの確認&#10;&lt;/h3&gt;&lt;p&gt;コマンドを実行する前に、カレントディレクトリが正しいかを確認することが大切です。&lt;code&gt;pwd&lt;/code&gt; コマンドを使用して現在のディレクトリを確認し、必要に応じて &lt;code&gt;cd&lt;/code&gt; コマンドで移動してください。これは、意図しないディレクトリのファイルを誤って操作することを防ぐためです。&lt;/p&gt;&#10;&lt;h3 id="ファイルのバックアップ"&gt;ファイルのバックアップ&#10;&lt;/h3&gt;&lt;p&gt;特に大切なデータを扱う場合、コマンドを実行する前にファイルのバックアップを取ることを強くお勧めします。これにより、万が一の事態が発生した場合でもデータを保護することができます。&lt;/p&gt;&#10;&lt;h3 id="ファイル名の特殊文字"&gt;ファイル名の特殊文字&#10;&lt;/h3&gt;&lt;p&gt;ファイル名にスペースや特殊文字が含まれている場合、これらを適切に処理するためにはファイル名をダブルクォートで囲むことが重要です。これは、シェルがファイル名を正しく解釈するために必要です。&lt;/p&gt;&#10;&lt;p&gt;これらの注意点を頭に入れておくことで、&lt;code&gt;.lzh&lt;/code&gt; ファイルの展開を安全かつ効率的に行うことができます。次のセクションでは、今回学んだ内容をまとめ、日常的なタスクの自動化の観点からこれらのコマンドの利用価値を評価します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事では、BashおよびFishシェルを用いてカレントディレクトリにある全ての&lt;code&gt;.lzh&lt;/code&gt;ファイルを効率的に展開する方法について学びました。Bashはその強力なスクリプティング能力で広く利用されており、Fishはユーザーフレンドリーな構文と使い勝手の良さで注目されています。どちらのシェルも、&lt;code&gt;.lzh&lt;/code&gt;ファイルのような特定のファイルタイプを扱う際に、効率的で強力なツールです。&lt;/p&gt;&#10;&lt;h3 id="bashとfishの比較"&gt;BashとFishの比較&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Bash&lt;/strong&gt;: 従来からのLinuxユーザーにとって馴染み深い。スクリプティングにおける複雑なタスクを処理するのに適しており、広範囲にわたる機能を提供します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Fish&lt;/strong&gt;: シンプルで直感的な構文を持つ新しいシェル。自動補完やシンタックスハイライトなどの便利な機能が標準で備わっており、シェルスクリプティング初心者にも扱いやすいです。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="自動化と効率化"&gt;自動化と効率化&#10;&lt;/h3&gt;&lt;p&gt;このようなシェルコマンドを使うことで、日常的に発生する繰り返しのタスクを自動化し、作業効率を大幅に向上させることが可能です。特に多くのアーカイブファイルを扱う場合、これらのコマンドを使うことで、手作業による時間の浪費を避け、より重要なタスクに集中することができます。&lt;/p&gt;&#10;&lt;h3 id="結論"&gt;結論&#10;&lt;/h3&gt;&lt;p&gt;BashとFishを使った&lt;code&gt;.lzh&lt;/code&gt;ファイルの展開方法は、日々の作業をスムーズに進めるための有効な手段です。シェルスクリプティングは、単なるコマンドライン操作以上の可能性を秘めており、これを習得することは、あらゆるIT専門家にとって価値のあるスキルです。&lt;/p&gt;&#10;&lt;p&gt;この記事が、BashとFishの使い方を理解し、より効率的なワークフローを構築する一助となれば幸いです。&lt;/p&gt;&#10;</description></item><item><title>direnvを活用したAWSアカウントの自動切り替え方法</title><link>https://ai.hack-le.com/direnv-aws/</link><pubDate>Sun, 10 Dec 2023 00:39:39 +0900</pubDate><guid>https://ai.hack-le.com/direnv-aws/</guid><description>&lt;p&gt;クラウドリソースを頻繁に使用する場合、異なるプロジェクトやクライアントごとに異なるAWSアカウントを切り替える必要があることは珍しくありません。この記事では、開発環境におけるAWSアカウントの自動切り替えを実現するために&lt;code&gt;direnv&lt;/code&gt;というツールの使用方法に焦点を当てます。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;は、シェル環境においてディレクトリごとに環境変数を自動で切り替えることができる非常に便利なツールです。これにより、プロジェクトや作業環境に応じて、AWSプロファイルや他の環境設定を簡単に切り替えることが可能になります。この記事では、&lt;code&gt;direnv&lt;/code&gt;の基本的なインストール方法から、AWSアカウントの切り替え設定までをステップバイステップで説明していきます。&lt;/p&gt;&#10;&lt;h2 id="direnvのインストールと設定"&gt;direnvのインストールと設定&#10;&lt;/h2&gt;&lt;p&gt;開発環境のカスタマイズにおいて、&lt;code&gt;direnv&lt;/code&gt;は非常に重要なツールの一つです。&lt;code&gt;direnv&lt;/code&gt;を使用すると、異なるディレクトリに移動した際に自動的に環境変数を切り替えることができ、特に複数のAWSアカウントを使い分ける際に大いに役立ちます。ここでは、&lt;code&gt;direnv&lt;/code&gt;のインストールと基本的な設定方法について説明します。&lt;/p&gt;&#10;&lt;h3 id="direnvのインストール"&gt;direnvのインストール&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;は多くのUnix系オペレーティングシステムで利用可能です。以下は、主要なOSにおける&lt;code&gt;direnv&lt;/code&gt;のインストール方法です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: Homebrewを使用して簡単にインストールできます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install direnv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Ubuntu/Debian&lt;/strong&gt;: aptパッケージマネージャを利用します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install direnv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Fedora&lt;/strong&gt;: dnfを使用してインストールします。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install direnv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="シェルにdirenvをフックする"&gt;シェルにdirenvをフックする&#10;&lt;/h3&gt;&lt;p&gt;インストール後、&lt;code&gt;direnv&lt;/code&gt;を使用するためにはシェルにフックする必要があります。これは、使用しているシェルの設定ファイルに特定の行を追加することで行います。以下は、いくつかの一般的なシェルの設定方法です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Bash (&lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.bash_profile&lt;/code&gt;)&lt;/strong&gt; :&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;direnv hook bash&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Zsh (&lt;code&gt;.zshrc&lt;/code&gt;)&lt;/strong&gt; :&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;direnv hook zsh&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Fish (&lt;code&gt;.config/fish/config.fish&lt;/code&gt;)&lt;/strong&gt; :&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;direnv hook fish&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらの設定を適用した後、シェルを再起動するか、新しいターミナルウィンドウを開いて設定を有効にします。&lt;/p&gt;&#10;&lt;h3 id="基本的な使用法"&gt;基本的な使用法&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;を使うための最初のステップは、環境変数や設定を含む&lt;code&gt;.envrc&lt;/code&gt;ファイルを作成することです。このファイルは、特定のディレクトリに配置され、&lt;code&gt;direnv&lt;/code&gt;によって自動的に読み込まれます。&lt;code&gt;.envrc&lt;/code&gt;ファイルには、AWSプロファイルの設定や他の必要な環境変数を指定できます。&lt;/p&gt;&#10;&lt;p&gt;セキュリティ上の理由から、新しい&lt;code&gt;.envrc&lt;/code&gt;ファイルは&lt;code&gt;direnv&lt;/code&gt;によってデフォルトで無視されます。ファイルを承認するためには、次のコマンドを使用します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;direnv allow .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、&lt;code&gt;.envrc&lt;/code&gt;ファイルが安全であることを&lt;code&gt;direnv&lt;/code&gt;に伝え、そのディレクトリでの変更を有効にします。&lt;/p&gt;&#10;&lt;h2 id="direnvを使用したawsアカウントの実践例とトラブルシューティング"&gt;direnvを使用したAWSアカウントの実践例とトラブルシューティング&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;を活用することで、AWSアカウントの切り替えをスムーズに行うことができます。このセクションでは、実際の使用例と一般的な問題の解決方法について説明します。&lt;/p&gt;&#10;&lt;h3 id="実際の使用例"&gt;実際の使用例&#10;&lt;/h3&gt;&lt;p&gt;想定するシナリオは、異なるAWSアカウントを使用する複数のプロジェクトに取り組んでいる状況です。それぞれのプロジェクトディレクトリに&lt;code&gt;.envrc&lt;/code&gt;ファイルを作成し、適切なAWSプロファイル名を設定します。&lt;/p&gt;&#10;&lt;p&gt;例えば、プロジェクトAとプロジェクトBがあり、それぞれ異なるAWSアカウントを使用するとします。プロジェクトAのディレクトリの&lt;code&gt;.envrc&lt;/code&gt;には以下のように書きます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;projectA-profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同様に、プロジェクトBの&lt;code&gt;.envrc&lt;/code&gt;には：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;projectB-profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、各プロジェクトディレクトリに移動するだけで、&lt;code&gt;direnv&lt;/code&gt;が自動的にAWSプロファイルを適切なものに切り替えます。&lt;/p&gt;&#10;&lt;h3 id="トラブルシューティングのヒント"&gt;トラブルシューティングのヒント&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;問題：&lt;code&gt;.envrc&lt;/code&gt;が読み込まれない&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;解決策：&lt;code&gt;direnv allow&lt;/code&gt;コマンドを使用して、&lt;code&gt;.envrc&lt;/code&gt;ファイルを承認します。また、シェルの設定ファイル（例：&lt;code&gt;.bashrc&lt;/code&gt;、&lt;code&gt;.zshrc&lt;/code&gt;、&lt;code&gt;.config/fish/config.fish&lt;/code&gt;）で&lt;code&gt;direnv&lt;/code&gt;が正しくフックされていることを確認してください。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;問題：AWSプロファイルが切り替わらない&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;解決策：&lt;code&gt;AWS_PROFILE&lt;/code&gt;変数が正しく設定されているか確認します。また、AWS CLIがインストールされていること、および&lt;code&gt;~/.aws/credentials&lt;/code&gt;と&lt;code&gt;~/.aws/config&lt;/code&gt;に正しい認証情報が設定されていることを確認してください。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;問題：セキュリティ上の懸念&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;解決策：&lt;code&gt;.envrc&lt;/code&gt;ファイルに機密情報（例：アクセスキー、シークレットキー）を直接書かないようにします。代わりに、プロファイル名のみを使用し、認証情報は&lt;code&gt;~/.aws/credentials&lt;/code&gt;に安全に保存します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;を使用したAWSプロファイルの自動切り替えの方法について詳しく説明しました。この手法は、複数のAWSアカウントを扱う際の生産性を高め、エラーの可能性を減らすのに役立ちます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;主なポイントの再確認&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;direnv&lt;/code&gt;をインストールし、シェルにフックする。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;.envrc&lt;/code&gt;ファイルを使用して、ディレクトリごとに異なるAWSプロファイルを設定する。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;direnv allow&lt;/code&gt;を実行して、新しい&lt;code&gt;.envrc&lt;/code&gt;ファイルを承認する。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;応用例&lt;/strong&gt;: この手法はAWSプロファイルに限らず、他の環境変数や設定（例えば、データベース接続設定やAPIキー）の管理にも応用できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティ上の注意&lt;/strong&gt;: &lt;code&gt;.envrc&lt;/code&gt;ファイルに機密情報を直接記述することは避け、安全な方法で認証情報を管理することが重要です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;参考記事&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;direnv公式ドキュメント&lt;/strong&gt;: &lt;a class="link" href="https://direnv.net/" target="_blank" rel="noopener"&#10; &gt;direnv公式ウェブサイト&lt;/a&gt;には、インストール方法、使用方法、さまざまな設定オプションに関する詳細情報があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS CLI公式ドキュメント&lt;/strong&gt;: AWS CLIの使用方法に関する詳細情報は、&lt;a class="link" href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html" target="_blank" rel="noopener"&#10; &gt;AWS公式ドキュメント&lt;/a&gt;で提供されています。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;関連ブログ記事やフォーラム&lt;/strong&gt;: コミュニティの経験やベストプラクティスを共有する多くのブログ記事やフォーラムが存在します。これらは、具体的なシナリオや高度な使用例を理解するのに役立つかもしれません。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Dockerを活用したGrafanaとElasticsearchの構築チュートリアル</title><link>https://ai.hack-le.com/docker-grafana-elasticsearch/</link><pubDate>Sun, 03 Dec 2023 22:04:02 +0900</pubDate><guid>https://ai.hack-le.com/docker-grafana-elasticsearch/</guid><description>&lt;p&gt;本チュートリアルでは、Dockerを介してセットアップし、Elasticsearchに格納されたデータをGrafanaでどのように閲覧するかを初学者に向けてステップバイステップで説明します。&lt;/p&gt;&#10;&lt;p&gt;このチュートリアルを通じて、読者は以下を学ぶことができるでしょう：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;DockerとDocker Composeを使用してGrafanaとElasticsearchを稼働させる方法&lt;/li&gt;&#10;&lt;li&gt;Elasticsearchにサンプルデータを投入してインデックスを作成する方法&lt;/li&gt;&#10;&lt;li&gt;GrafanaでElasticsearchをデータソースとして設定し、データをクエリする方法&lt;/li&gt;&#10;&lt;li&gt;カスタマイズ可能なダッシュボードを作成し、データを視覚化する方法&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;チュートリアルを開始する前に、以下の前提条件を満たしていることを確認してください：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerがインストールされ、基本的な操作に慣れていること&lt;/li&gt;&#10;&lt;li&gt;基本的なコマンドライン操作に慣れていること&lt;/li&gt;&#10;&lt;li&gt;JSON形式とHTTPリクエストの基本的な知識があること&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このチュートリアルが終わる頃には、読者は自身のデータをGrafanaで視覚化するための基礎を固めることができるでしょう。それでは、Dockerでの環境構築から始めてみましょう。&lt;/p&gt;&#10;&lt;p&gt;著者環境&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Apple M2 Pro&lt;/li&gt;&#10;&lt;li&gt;macOS 14.1&lt;/li&gt;&#10;&lt;li&gt;Docker 24.0.6 ed22dbc&lt;/li&gt;&#10;&lt;li&gt;Docker Compose v2.23.0-desktop.1&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="セクション1-環境セットアップ"&gt;セクション1: 環境セットアップ&#10;&lt;/h2&gt;&lt;p&gt;成功的なデータ視覚化プロジェクトを始めるためには、まず堅固な基盤を築くことが必要です。このセクションでは、GrafanaとElasticsearchを動かすためのDocker環境のセットアップ方法について説明します。&lt;/p&gt;&#10;&lt;p&gt;Dockerは、アプリケーションをコンテナとしてパッケージ化し、あらゆる環境で一貫した動作を保証するためのプラットフォームです。まだDockerをお使いでない場合は、&lt;a class="link" href="https://www.docker.com/products/docker-desktop" target="_blank" rel="noopener"&#10; &gt;Dockerの公式ウェブサイト&lt;/a&gt;からインストーラーをダウンロードし、ご使用のオペレーティングシステム（Windows、macOS、Linux）に合わせたインストール手順に従ってください。&lt;/p&gt;&#10;&lt;p&gt;Dockerをインストールしたら、ターミナルまたはコマンドプロンプトを開き、以下のコマンドでバージョン情報を確認してDockerが正しくインストールされていることを確認してください。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker Composeは、複数のコンテナを定義し、実行するためのツールです。これにより、GrafanaとElasticsearchのような複数のサービスを組み合わせて動かすことが容易になります。Docker Desktopをインストールすると、通常はDocker Composeも一緒にインストールされます。バージョンを確認するには次のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GrafanaとElasticsearchをセットアップするためには、&lt;code&gt;docker-compose.yml&lt;/code&gt; というYAMLファイルを作成し、サービスの設定を記述します。このファイルでは、使用するDockerイメージ、公開するポート、永続化するデータのボリュームなどを定義します。&lt;/p&gt;&#10;&lt;p&gt;ファイル構造は通常以下のようになります：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── data/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── grafana/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── elasticsearch/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;：サービスの設定が記述されたメインのYAMLファイルです。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;data/&lt;/code&gt;：データを永続化するためのディレクトリで、サブディレクトリにはGrafanaとElasticsearchのデータが格納されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="セクション2-docker-composeを使用したelasticsearchのセットアップ"&gt;セクション2: Docker Composeを使用したElasticsearchのセットアップ&#10;&lt;/h2&gt;&lt;p&gt;データストレージとして機能するElasticsearchは、ログやメトリクスなどの様々なデータを集約して検索可能にする強力なツールです。このセクションでは、ElasticsearchをDocker Composeでセットアップする方法を説明します。&lt;/p&gt;&#10;&lt;p&gt;Elasticsearchの公式Dockerイメージは&lt;a class="link" href="https://hub.docker.com/_/elasticsearch" target="_blank" rel="noopener"&#10; &gt;Docker Hub&lt;/a&gt;から入手できます。最新版または特定のバージョンを選択して使用することができます。通常、最新版を使用することをお勧めしますが、互換性の都合上、特定のバージョンを使用する必要がある場合もあります。&lt;/p&gt;&#10;&lt;p&gt;プロジェクトのルートディレクトリに&lt;code&gt;docker-compose.yml&lt;/code&gt;ファイルを作成し、以下のような内容を記述します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;version: &lt;span class="s1"&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; elasticsearch:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: docker.elastic.co/elasticsearch/elasticsearch:7.17.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: elasticsearch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - discovery.type&lt;span class="o"&gt;=&lt;/span&gt;single-node&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ./data/elasticsearch:/usr/share/elasticsearch/data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - &lt;span class="s2"&gt;&amp;#34;9200:9200&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - esnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; esnet:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; driver: bridge&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このファイルでは、シングルノードクラスタとして機能するElasticsearchインスタンスを定義しています。データを永続化するためにボリュームをマウントし、9200番ポートを公開して外部からのアクセスを可能にしています。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;ファイルが用意できたら、以下のコマンドを実行してElasticsearchコンテナを起動します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;起動後、コンテナの健全性を確認するには、ブラウザまたはcurlコマンドを使用してElasticsearchのヘルスステータスをチェックします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X GET &lt;span class="s2"&gt;&amp;#34;localhost:9200/_cluster/health&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;応答にはElasticsearchクラスタのヘルスステータスが含まれており、&lt;code&gt;green&lt;/code&gt;、&lt;code&gt;yellow&lt;/code&gt;、&lt;code&gt;red&lt;/code&gt;のいずれかのステータスが表示されます。&lt;code&gt;green&lt;/code&gt;は全てが正常であることを、&lt;code&gt;yellow&lt;/code&gt;は一部のレプリカが利用できないことを、&lt;code&gt;red&lt;/code&gt;はクラスタが正常に機能していないことを示します。&lt;/p&gt;&#10;&lt;h2 id="セクション3-docker-composeを使用したgrafanaのセットアップ"&gt;セクション3: Docker Composeを使用したGrafanaのセットアップ&#10;&lt;/h2&gt;&lt;p&gt;データ視覚化プラットフォームであるGrafanaは、複雑なデータセットからの洞察を提供するインタラクティブなダッシュボードを作成するのに最適です。このセクションでは、GrafanaをDocker Composeでセットアップし、データ視覚化のための基盤を構築する方法を説明します。&lt;/p&gt;&#10;&lt;p&gt;Grafanaの公式Dockerイメージは&lt;a class="link" href="https://hub.docker.com/r/grafana/grafana/" target="_blank" rel="noopener"&#10; &gt;Docker Hub&lt;/a&gt;から入手できます。最新版または特定のバージョンを選択して使用することができます。安定した運用を望む場合は、リリースされたばかりの最新版ではなく、広くテストされているバージョンを選択することを推奨します。&lt;/p&gt;&#10;&lt;p&gt;既に作成した&lt;code&gt;docker-compose.yml&lt;/code&gt;ファイルに、Grafanaのサービス定義を追加します。ファイルは以下のように拡張されます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;version: &lt;span class="s1"&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; elasticsearch:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ... Elasticsearchの設定 ...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; grafana:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; image: grafana/grafana-enterprise&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; container_name: grafana&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - elasticsearch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ./data/grafana:/var/lib/grafana&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - &lt;span class="s2"&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - esnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; esnet:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; driver: bridge&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで、Grafanaの永続化のためにボリュームをマウントし、3000番ポートを公開してアクセスを可能にしています。&lt;code&gt;depends_on&lt;/code&gt;キーを使って、GrafanaがElasticsearchに依存するように定義しているため、Elasticsearchが先に起動します。&lt;/p&gt;&#10;&lt;p&gt;Grafanaサービスの設定を追加したら、以下のコマンドでGrafanaコンテナを起動します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d grafana&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;コンテナが起動したら、ブラウザを開いて &lt;code&gt;http://localhost:3000&lt;/code&gt; にアクセスし、Grafanaのダッシュボードにログインします。初期ユーザー名は「admin」、パスワードは&lt;code&gt;docker-compose.yml&lt;/code&gt;ファイルで設定した値（この例では&lt;code&gt;yourpassword&lt;/code&gt;）です。&lt;/p&gt;&#10;&lt;p&gt;これでGrafanaの基本的なセットアップは完了です。ダッシュボードにログイン後、データソースを追加し、クエリを作成してデータを視覚化する準備が整いました。&lt;/p&gt;&#10;&lt;h2 id="セクション4-elasticsearchにサンプルデータの投入"&gt;セクション4: Elasticsearchにサンプルデータの投入&#10;&lt;/h2&gt;&lt;p&gt;データを視覚化するためには、まずはElasticsearchにデータが存在している必要があります。このセクションでは、サンプルデータを生成し、Elasticsearchにデータを投入する方法を説明します。&lt;/p&gt;&#10;&lt;p&gt;サンプルデータは、実際のユースケースを模倣することができるランダムな値で構成されます。以下のようなJSON形式でデータを作成します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;2023-01-01T00:00:00Z&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span class="m"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで&lt;code&gt;timestamp&lt;/code&gt;はISO 8601形式で、&lt;code&gt;value&lt;/code&gt;はデータの値です。シェルスクリプトやPythonスクリプトを利用して、これらのデータを一定間隔で生成し、Elasticsearchに投入することができます。&lt;/p&gt;&#10;&lt;p&gt;サンプルデータをElasticsearchに投入するには、&lt;code&gt;curl&lt;/code&gt;コマンドやPostmanなどのHTTPクライアントを使用して、HTTP POSTリクエストを行います。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X POST &lt;span class="s2"&gt;&amp;#34;localhost:9200/my-index/_doc&amp;#34;&lt;/span&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -d&lt;span class="s1"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;timestamp&amp;#34;: &amp;#34;2023-12-03T12:00:00Z&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;value&amp;#34;: 100&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、現在のUTC時刻とランダムな&lt;code&gt;value&lt;/code&gt;値を持つJSONデータを&lt;code&gt;my-index&lt;/code&gt;インデックスに投入します。&lt;/p&gt;&#10;&lt;p&gt;データがElasticsearchに正しく投入されたことを確認するには、以下のようなクエリを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X GET &lt;span class="s2"&gt;&amp;#34;http://localhost:9200/my-index/_search?pretty&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、&lt;code&gt;my-index&lt;/code&gt;インデックスに格納されたデータのサンプルを返します。&lt;code&gt;pretty&lt;/code&gt;パラメータは、読みやすい形式で結果を表示するためのものです。&lt;/p&gt;&#10;&lt;p&gt;データが期待通りにElasticsearchに格納されていることを確認したら、次はGrafanaでこれらのデータを視覚化する準備が整います。&lt;/p&gt;&#10;&lt;h2 id="セクション5-grafanaでのelasticsearchデータソースの設定"&gt;セクション5: GrafanaでのElasticsearchデータソースの設定&#10;&lt;/h2&gt;&lt;p&gt;データがElasticsearchに投入されたので、次はGrafanaでそれを視覚化するためのデータソースを設定します。このプロセスは、Grafanaの機能を活用して、データをクエリし、分析するための基盤を作ります。&lt;/p&gt;&#10;&lt;p&gt;まず、Grafanaのウェブインターフェイスにアクセスします。デフォルトでは、Grafanaはポート3000で実行されますので、ブラウザで &lt;code&gt;http://localhost:3000&lt;/code&gt; を開きます。ログイン画面が表示されたら、初期設定で定められたユーザー名（デフォルトでは&lt;code&gt;admin&lt;/code&gt;）とパスワード（こちらも &lt;code&gt;admin&lt;/code&gt; で、最初に初期パスワードを設定します）を使用してログインします。&lt;/p&gt;&#10;&lt;p&gt;Grafanaダッシュボードの左サイドバーからメニューをクリックし、「Connections」「Data Sources」を選択します。画面の「Add data source」ボタンをクリックし、リストから「Elasticsearch」を選びます。&lt;/p&gt;&#10;&lt;p&gt;Elasticsearchの設定ページで、以下の情報を入力します。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: データソースの名前を入力します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;URL&lt;/strong&gt;: ElasticsearchインスタンスのURLを入力します。この例では、&lt;code&gt;http://elasticsearch:9200&lt;/code&gt; となります（Docker Composeで定義したサービス名を使用）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Index name&lt;/strong&gt;: Elasticsearchでデータを格納したインデックス名を入力します。この例では、&lt;code&gt;my-index&lt;/code&gt; です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Time Field name&lt;/strong&gt;: Elasticsearchのタイムスタンプフィールド名を入力します。この例では、&lt;code&gt;timestamp&lt;/code&gt; です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;全ての情報を入力したら、「Save &amp;amp; Test」ボタンをクリックして、GrafanaがElasticsearchに接続できるかテストします。成功すれば、接続が確立され、データソースとして使用できるようになります。&lt;/p&gt;&#10;&lt;h2 id="セクション6-grafanaでのダッシュボードとパネルの作成"&gt;セクション6: Grafanaでのダッシュボードとパネルの作成&#10;&lt;/h2&gt;&lt;p&gt;Grafanaでデータソースを設定した後、次のステップはダッシュボードを作成し、Elasticsearchからのデータを視覚化するパネルを追加することです。このセクションでは、そのプロセスをステップバイステップで説明します。&lt;/p&gt;&#10;&lt;p&gt;Grafanaのメインメニューから「Dashboard」「Create Dashboard」「Add visualization」をクリックして新しいダッシュボードを作成します。新しいダッシュボードが開いたら、Elasticsearchをデータソースとして指定します。&lt;/p&gt;&#10;&lt;p&gt;パネルエディタが開いたら、次のように設定を行います：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;データソースの選択&lt;/strong&gt;: 前のセクションで設定したElasticsearchデータソースを選択します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;クエリの構築&lt;/strong&gt;: 「Query」セクションで、Elasticsearchから取得したいデータにマッチするクエリを構築します。ここで、特定のフィールドの値や時間フィルターを指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;視覚化の選択&lt;/strong&gt;: 「Visualization」タブでグラフの種類を選択します。時系列データを表示するには「Time series」が適しています。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;パネルのカスタマイズ&lt;/strong&gt;: 「Panel Title」に適切な名前を入力し、その他の視覚的要素（軸のラベル、色、レジェンドなど）をカスタマイズします。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;時系列データを視覚化する場合、通常、データポイントがどのように時間とともに変化するかを示す折れ線グラフを使用します。以下の設定を確認し、必要に応じて調整します：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Metric&lt;/strong&gt;: データソースから「value」フィールドを選択し、集計方法として「Average」や「Max」を選ぶことができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Group By&lt;/strong&gt;: 「Date Histogram」を選択し、適切な「Interval」を設定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Time Range&lt;/strong&gt;: ダッシュボード右上の時間範囲を設定し、表示したいデータの時間枠を選択します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2023/12/d1d5719b66f8a0f31170d270a090cf79-1024x925.png"&gt;&lt;/p&gt;&#10;&lt;p&gt;すべての設定が完了したら、画面右上にある「Save」ボタンをクリックしてダッシュボードを保存します。保存時にはダッシュボードに名前をつけ、必要に応じて詳細な説明を加えることができます。&lt;/p&gt;&#10;&lt;h2 id="セクション7-大量のサンプルデータの投入と折れ線グラフの表示"&gt;セクション7: 大量のサンプルデータの投入と折れ線グラフの表示&#10;&lt;/h2&gt;&lt;p&gt;データ視覚化の実践的な学習には、現実的なデータセットの使用が不可欠です。このセクションでは、大量のサンプルデータをElasticsearchに投入し、それをGrafanaで折れ線グラフとして表示する方法を説明します。&lt;/p&gt;&#10;&lt;p&gt;サンプルデータを生成するには、スクリプトを使用して一定期間ごとにデータポイントを生成し、Elasticsearchに送信する方法が効果的です。以下は、簡単なbashスクリプトの例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ElasticsearchのURLとインデックス名&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ES_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://localhost:9200&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;INDEX_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-index&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 現在のUNIXタイムスタンプを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;current_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date +%s&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1分ごとのデータを過去24時間分生成&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; i in &lt;span class="o"&gt;{&lt;/span&gt;0..1439&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;$current_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;$RANDOM&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -X POST &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$ES_URL&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$INDEX_NAME&lt;/span&gt;&lt;span class="s2"&gt;/_doc&amp;#34;&lt;/span&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -d @- &lt;span class="s"&gt;&amp;lt;&amp;lt; EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;timestamp&amp;#34;: &amp;#34;$(date -r $timestamp +&amp;#34;%Y-%m-%dT%H:%M:%SZ&amp;#34;)&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;value&amp;#34;: $value&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このスクリプトは、現在時刻から過去24時間にわたるランダムな&lt;code&gt;value&lt;/code&gt;を持つデータポイントを生成し、Elasticsearchに投入します。&lt;/p&gt;&#10;&lt;p&gt;Grafanaでさきほどのダッシュボードについて、設定を変更します。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Metric: Max、フィールドを &lt;code&gt;value&lt;/code&gt;にします。&lt;/li&gt;&#10;&lt;li&gt;Options: Intervalを1mにします。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;以下のように時系列データの折れ線グラフを確認できます。&lt;/p&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2023/12/7ffecc2ec0f02971ee5a88ba284b0344-1024x1020.png"&gt;&lt;/p&gt;&#10;&lt;h2 id="セクション8-環境のクリーンアップ"&gt;セクション8: 環境のクリーンアップ&#10;&lt;/h2&gt;&lt;p&gt;チュートリアルを完了した後、Docker環境をクリーンアップすることが重要です。このセクションでは、GrafanaとElasticsearchのDockerコンテナを安全に停止し、関連するデータをクリーンアップする方法について説明します。&lt;/p&gt;&#10;&lt;p&gt;GrafanaとElasticsearchのコンテナを停止するには、以下のコマンドを実行します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose down&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、&lt;code&gt;docker-compose.yml&lt;/code&gt;ファイルに記述されたすべてのサービスを停止し、コンテナを削除します。また、Docker Composeによって作成されたネットワークも同時に削除されます。ただし、コンテナを停止しても、Dockerボリュームに保存されたデータは保持されます。&lt;/p&gt;&#10;&lt;p&gt;Docker環境のクリーンアップは、システムリソースの節約や、新しいプロジェクトを始める際の準備として重要です。上記の手順に従って、不要になったコンテナ、ボリューム、ネットワークを適切に削除し、システムをクリーンな状態に保ちましょう。&lt;/p&gt;&#10;&lt;p&gt;続けて、「セクション9: まとめとさらなる学習へのステップ」というセクションを詳しく書き出します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="セクション9-まとめとさらなる学習へのステップ"&gt;セクション9: まとめとさらなる学習へのステップ&#10;&lt;/h2&gt;&lt;p&gt;このチュートリアルを通じて、Dockerを使ったGrafanaとElasticsearchのセットアップから、データの視覚化、ダッシュボードのカスタマイズ、環境のクリーンアップに至るまでの一連のプロセスを学びました。ここでは、このチュートリアルの主要なポイントを振り返り、さらなる学習への道を案内します。&lt;/p&gt;&#10;&lt;h3 id="主要な学習ポイント"&gt;主要な学習ポイント&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;DockerとDocker Composeの基本&lt;/strong&gt;: GrafanaとElasticsearchを簡単にセットアップし、運用する方法を学びました。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;データの投入とインデックス作成&lt;/strong&gt;: Elasticsearchにサンプルデータを投入し、データが適切にインデックスされていることを確認しました。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;データソースとダッシュボードの設定&lt;/strong&gt;: GrafanaでElasticsearchをデータソースとして追加し、データを視覚化するためのダッシュボードを作成しました。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;クリーンアップ&lt;/strong&gt;: 使用した環境を適切にクリーンアップし、リソースを解放しました。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="さらなる学習への推奨"&gt;さらなる学習への推奨&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;公式ドキュメント&lt;/strong&gt;: GrafanaとElasticsearchの公式ドキュメントを読むことで、さらに深い知識を得ることができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コミュニティフォーラムとブログ&lt;/strong&gt;: 両ツールのコミュニティフォーラムやブログをフォローすることで、最新のヒントやトリック、ベストプラクティスを学ぶことができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;実践プロジェクト&lt;/strong&gt;: 実際のデータセットを使用して独自のダッシュボードを作成し、新しいスキルを実践的に適用してみましょう。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;GrafanaとElasticsearchは、データ駆動型の意思決定を支援する強力なツールです。このチュートリアルが、データ視覚化の旅における貴重な一歩となることを願っています。引き続き学習を進め、データの可能性を最大限に引き出してください。&lt;/p&gt;&#10;</description></item><item><title>DynamoDBでデータを自動削除：TTL設定のステップバイステップ</title><link>https://ai.hack-le.com/dynamodb-ttl/</link><pubDate>Tue, 28 Nov 2023 00:06:37 +0900</pubDate><guid>https://ai.hack-le.com/dynamodb-ttl/</guid><description>&lt;p&gt;現代のアプリケーション開発において、迅速かつ効率的なデータ管理は不可欠です。Amazon DynamoDBは、そのようなニーズを満たすために開発されたNoSQLデータベースサービスです。DynamoDBは、高い可用性と拡張性を提供し、大量のデータを素早く処理する能力があります。これにより、開発者はアプリケーションのパフォーマンスを最適化し、よりスムーズなユーザー体験を提供することができます。&lt;/p&gt;&#10;&lt;p&gt;この記事では、&lt;strong&gt;データが自動的に削除されるべき時点を定義する機能であるTTL（Time To Live）を利用し、DynamoDBで有効期限のあるデータを効率的に扱う方法&lt;/strong&gt;について掘り下げていきます。&lt;/p&gt;&#10;&lt;h2 id="ttlとは何か"&gt;TTLとは何か？&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;「Time To Live」（TTL）は、データがデータベース内で生存する時間の長さを指します&lt;/strong&gt;。具体的には、データ項目に設定された特定の時間が経過すると、そのデータは自動的にデータベースから削除されます。この時間は、通常、UNIXタイムスタンプ形式で指定されます。&lt;/p&gt;&#10;&lt;p&gt;TTLは、DynamoDBのようなNoSQLデータベース管理システムで特に有用です。これにより、データのライフサイクルを自動的に管理し、データベースのサイズとコストを効率的に管理することが可能になります。&lt;/p&gt;&#10;&lt;p&gt;TTL機能を活用することで、以下のような多くの利点があります。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;自動的なデータのクリーンアップ&lt;/strong&gt;: DynamoDBでは、TTLを設定することで、期限切れのデータを自動的に削除し、データの整合性を保つことができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ストレージコストの削減&lt;/strong&gt;: 不要なデータを自動的に削除することで、ストレージの使用量を減らし、コストを節約できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティリスクの軽減&lt;/strong&gt;: 古いデータや期限切れのデータはセキュリティリスクを引き起こす可能性があります。これらを自動的に削除することで、リスクを減少させることができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;システムパフォーマンスの最適化&lt;/strong&gt;: 不要なデータを削除することで、データベースの応答性とパフォーマンスが向上します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コンプライアンスのサポート&lt;/strong&gt;: 特定の業界規制では、データの保持期間に厳格な制限がある場合があります。TTLを用いることで、これらの規制要件を自動的に満たすことが可能になります。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="dynamodbにおけるttlの利用方法"&gt;DynamoDBにおけるTTLの利用方法&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBでTTLを設定するプロセスは、シンプルかつ直感的です。主なステップは以下の通りです。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;TTL属性の選択&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;DynamoDBのテーブルには、TTLのための特定の属性（列）が必要です。これは、各アイテムがどのタイミングで削除されるべきかを示すUNIXエポックタイムスタンプを格納します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWSコンソールでのTTL設定&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;AWSマネジメントコンソールを使用して、TTLを有効にします。テーブルを選択し、TTL属性を指定して、TTLを有効化するオプションを選びます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;TTL値の設定&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;新しいアイテムをテーブルに追加する際、または既存のアイテムを更新する際に、TTL属性にUNIXタイムスタンプを設定します。このタイムスタンプは、アイテムが自動的に削除されるべき時刻を表します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;TTL属性の設定は、アイテムの追加や更新時に行われます。例えば、セッションデータや一時的なトークンなど、一定期間後に自動的に削除したいデータに対して効果的です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: セッションが1時間後に期限切れになるように設定する場合、TTL属性には現在のUNIXタイムスタンプに3600秒（1時間）を加えた値を設定します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ttlの実践的な使用例"&gt;TTLの実践的な使用例&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBのTTL機能は、多くの実用的なシナリオで有効です。ここでは、特に一般的な使用例としてセッション管理とトークン管理を取り上げます。&lt;/p&gt;&#10;&lt;h3 id="セッション管理"&gt;セッション管理&#10;&lt;/h3&gt;&lt;p&gt;ウェブアプリケーションやモバイルアプリケーションでは、ユーザーのセッション情報を管理する必要があります。セッションは、特定の期間の活動後に期限切れになるべきです。DynamoDBのTTLを利用して、期限切れのセッションデータを自動的に削除することで、セキュリティを強化し、データの整理を効率的に行うことができます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: ユーザーがログインすると、セッションデータがDynamoDBに保存され、TTL属性には現在時刻から数時間後のタイムスタンプが設定されます。この期間が経過すると、セッションデータは自動的に削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="トークン管理"&gt;トークン管理&#10;&lt;/h3&gt;&lt;p&gt;APIトークンや一時的な認証コードなど、一定期間後に無効化されるべきトークンも、TTLを利用して管理することができます。これにより、期限切れのトークンがシステム内に残らないようにし、セキュリティを向上させることが可能です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: ユーザーがパスワードリセットを要求すると、一時的な認証コードが生成され、TTL属性には短い期限（例えば30分後）が設定されます。この期限が経過すると、認証コードは自動的に削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="期限切れデータの自動削除"&gt;期限切れデータの自動削除&#10;&lt;/h3&gt;&lt;p&gt;TTLは、特に期限が設定されたデータ（例えば、プロモーション情報やイベント情報）に有効です。イベントが終了したり、プロモーションが終了した後に自動的にデータを削除することで、データの整合性を保ち、不要なデータの蓄積を防ぐことができます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: 特定のイベントに関連するデータには、イベント終了日のタイムスタンプがTTL属性として設定されます。イベント終了後、これらのデータは自動的に削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ttlの使用時に考慮すべき点"&gt;TTLの使用時に考慮すべき点&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBでのTTL機能の使用は、多くの利点を提供しますが、その実装と管理には注意が必要です。以下に、TTLを使用する際に考慮すべきいくつかの重要な点を挙げます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;適切なタイムスタンプの使用&lt;/strong&gt;: TTL属性に設定されるUNIXタイムスタンプは正確でなければなりません。誤ったタイムスタンプは、データの早すぎる削除や予定された削除の遅延を引き起こす可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;非同期的な削除&lt;/strong&gt;: TTLによる削除は非同期で行われるため、設定された時刻を過ぎた直後にアイテムが削除されるわけではありません。この遅延は、アプリケーションのロジックに影響を与える可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;パフォーマンスへの影響&lt;/strong&gt;: 大量のアイテムが同時に削除される場合、一時的にテーブルのパフォーマンスに影響を与える可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コスト削減&lt;/strong&gt;: 不要なデータを削除することでストレージコストを削減できますが、TTL設定自体の管理にもリソースが必要です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ttlの最適な活用法"&gt;TTLの最適な活用法&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBのTTL機能を最大限に活用するためには、戦略的なアプローチが必要です。以下に、TTLを効果的に使用するためのベストプラクティスを紹介します。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;データの種類と重要性の評価&lt;/strong&gt;: データの種類によって、その保持期間は異なります。例えば、セッションデータや一時的なトークンは短期間で削除するのが適していますが、顧客情報や取引記録は長期間保持する必要があるかもしれません。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ビジネス要件と規制の遵守&lt;/strong&gt;: ビジネスの要件と規制上の要件に基づいてTTLポリシーを設定します。これにより、データの整合性とコンプライアンスを確保できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;複雑なロジックの適用&lt;/strong&gt;: すべてのデータがTTLによる単純な削除ルールに適合しない場合、バッチ処理を利用してより複雑な削除ロジックを適用することができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;非同期処理の活用&lt;/strong&gt;: バッチ処理を非同期で実行し、データベースのパフォーマンスに与える影響を最小限に抑えることが重要です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;パフォーマンスへの影響のモニタリング&lt;/strong&gt;: TTLによる削除操作がテーブルのパフォーマンスに与える影響を定期的にモニタリングし、必要に応じて調整します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;負荷の分散&lt;/strong&gt;: 削除操作がテーブルに集中することを避けるために、負荷を分散させる戦略を検討します。これには、データの分割や異なるテーブルへの配置が含まれます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBのTTL機能は、データのライフサイクル管理を自動化し、ストレージコストを削減し、セキュリティを強化するための強力なツールです。適切に設定され、効果的に管理されたTTLは、データベースの整理と最適化に大きな貢献をします。しかし、その利用には、ビジネスの要件、データの種類、およびセキュリティとコンプライアンスの要件を考慮する必要があります。戦略的なアプローチをとることで、TTLはDynamoDBを使用するアプリケーションの効率を大幅に向上させることができます。&lt;/p&gt;&#10;</description></item><item><title>Macで自動化する：launchdを使ってスクリプトを起動時に実行する方法</title><link>https://ai.hack-le.com/mac-launchd/</link><pubDate>Sun, 26 Nov 2023 21:30:13 +0900</pubDate><guid>https://ai.hack-le.com/mac-launchd/</guid><description>&lt;h2 id="導入"&gt;導入&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Mac OSでは、&lt;code&gt;launchd&lt;/code&gt;という強力なシステムが組み込まれています&lt;/strong&gt;。これは、さまざまなタスクを自動化するためのツールで、特にシステムの起動時や特定の条件下でプログラムやスクリプトを自動的に実行するのに適しています。&lt;code&gt;launchd&lt;/code&gt;はMacのバックグラウンドで動作し、ユーザーが意識することなく様々なプロセスを管理します。&lt;/p&gt;&#10;&lt;p&gt;この記事では、&lt;code&gt;launchd&lt;/code&gt;を使用して、Macが起動するたびに特定のスクリプトを自動的に実行する方法について詳しく説明します。&lt;/p&gt;&#10;&lt;p&gt;定期実行はこちら&lt;/p&gt;&#10;&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/macos-launchd-schedule/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;macOSのlaunchdでスクリプトを定期実行するplistのメモ&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/macos-launchd-schedule/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2024/09/macos-launchd-schedule.webp" alt="macOSのlaunchdでスクリプトを定期実行するplistのメモ" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;h2 id="スクリプトの準備"&gt;スクリプトの準備&#10;&lt;/h2&gt;&lt;p&gt;自動化の旅を始める前に、まずは実行したいスクリプトを用意する必要があります。このステップでは、単純なシェルスクリプトを作成し、それをMacの起動時に実行する方法に焦点を当てます。シェルスクリプトは、簡単で理解しやすいので、自動化の基本を学ぶのに最適です。&lt;/p&gt;&#10;&lt;p&gt;以下は、非常に基本的なシェルスクリプトの例です。このスクリプトは、「Hello, World!」というメッセージをログファイルに書き込みます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt; &amp;gt; /path/to/your/logfile.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このスクリプトをテキストエディタで作成し、「myscript.sh」という名前で保存します。保存場所は、例えばホームディレクトリ内の&lt;code&gt;Scripts&lt;/code&gt;フォルダなど、容易にアクセスできる場所が適しています。&lt;/p&gt;&#10;&lt;p&gt;作成したスクリプトは、実行可能でなければなりません。これを行うには、ターミナルで次のコマンドを使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x ~/Scripts/myscript.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドにより、&lt;code&gt;myscript.sh&lt;/code&gt;に実行権限が付与されます。これでスクリプトは&lt;code&gt;launchd&lt;/code&gt;によって起動時に実行される準備が整いました。&lt;/p&gt;&#10;&lt;h2 id="plistファイルの作成と設定"&gt;.plistファイルの作成と設定&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;launchd&lt;/code&gt;を使用する際の重要な要素が&lt;code&gt;.plist&lt;/code&gt;（プロパティリスト）ファイルです。このXML形式のファイルは、&lt;code&gt;launchd&lt;/code&gt;に対して、どのスクリプトをいつ実行するか、そしてどのように実行するかを指示します。正しく設定された.plistファイルは、スクリプトを自動的に、そして安全に実行するための鍵となります。&lt;/p&gt;&#10;&lt;p&gt;ここでは、先に作成した&lt;code&gt;myscript.sh&lt;/code&gt;を起動時に実行するための.plistファイルの例を示します。以下のコードをテキストエディタで作成し、適切な名前（例：&lt;code&gt;com.yourusername.myscript.plist&lt;/code&gt;）で保存します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;?xml &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;?&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;!DOCTYPE plist PUBLIC &lt;span class="s2"&gt;&amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;plist &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;com.yourusername.myscript&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/Users/yourusername/Scripts/myscript.sh&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;/array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;true/&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/plist&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このファイルでは、&lt;code&gt;Label&lt;/code&gt;はユニークな識別子を提供し、&lt;code&gt;ProgramArguments&lt;/code&gt;は実行するスクリプトのパスを指定します。&lt;code&gt;RunAtLoad&lt;/code&gt;が&lt;code&gt;true&lt;/code&gt;に設定されていると、Macが起動するたびにスクリプトが実行されます。&lt;/p&gt;&#10;&lt;p&gt;作成した.plistファイルを&lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt;ディレクトリに保存します。この場所にファイルを置くことで、ユーザーがログインした際に自動的に&lt;code&gt;launchd&lt;/code&gt;によって読み込まれ、スクリプトが実行されるようになります。&lt;/p&gt;&#10;&lt;h2 id="plistファイルの作成と設定引数を含むスクリプトの場合"&gt;.plistファイルの作成と設定（引数を含むスクリプトの場合）&#10;&lt;/h2&gt;&lt;p&gt;スクリプトが引数を必要とする場合、それらの引数を.plistファイルに正しく組み込むことが重要です。例として、引数を受け取りログファイルに出力するシンプルなスクリプトを考えてみましょう。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Passed argument: &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &amp;gt; /path/to/your/logfile.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このスクリプトは引数&lt;code&gt;$1&lt;/code&gt;を取り、それをログファイルに出力します。&lt;/p&gt;&#10;&lt;p&gt;引数を含むスクリプトを自動実行するための.plistファイルは、以下のようになります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;?xml &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;?&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;!DOCTYPE plist PUBLIC &lt;span class="s2"&gt;&amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;plist &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;com.yourusername.myscriptwithargs&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;/Users/yourusername/Scripts/myscript.sh&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;string&amp;gt;Argument1&amp;lt;/string&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;/array&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;true/&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/dict&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/plist&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この例では、&lt;code&gt;ProgramArguments&lt;/code&gt;キーの配列に、スクリプトのパスと引数&lt;code&gt;Argument1&lt;/code&gt;が含まれています。この設定により、スクリプトは指定した引数を持って起動時に実行されます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;引数が正しくスクリプトに渡されることを確認するため、事前に手動でスクリプトをテストしてください。&lt;/li&gt;&#10;&lt;li&gt;引数の値が変わる場合は、その都度.plistファイルを更新し、再度&lt;code&gt;launchctl&lt;/code&gt;を使って登録する必要があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このセクションでは、引数を含むスクリプトの自動実行に必要な.plistファイルの作成方法を示しました。次のセクションでは、これらの.plistファイルを実際に&lt;code&gt;launchd&lt;/code&gt;に登録し、自動実行を設定する手順について詳しく解説します。&lt;/p&gt;&#10;&lt;h2 id="launchdにスクリプトを登録する"&gt;&lt;code&gt;launchd&lt;/code&gt;にスクリプトを登録する&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;.plist&lt;/code&gt;ファイルを作成し、適切なディレクトリに配置した後、次のステップは、このファイルを&lt;code&gt;launchd&lt;/code&gt;に登録することです。これには&lt;code&gt;launchctl&lt;/code&gt;コマンドが使用されます。以下のコマンドは、新しく作成した.plistファイルを&lt;code&gt;launchd&lt;/code&gt;に登録する例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl load ~/Library/LaunchAgents/com.yourusername.myscript.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、&lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt;にある&lt;code&gt;com.yourusername.myscript.plist&lt;/code&gt;という.plistファイルを&lt;code&gt;launchd&lt;/code&gt;に登録します。これにより、指定された条件（この場合はMacの起動時）にスクリプトが自動的に実行されます。&lt;/p&gt;&#10;&lt;p&gt;登録が正常に完了したかを確認するには、以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl list &lt;span class="p"&gt;|&lt;/span&gt; grep com.yourusername.myscript&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、登録されたジョブのリストから、指定した識別子&lt;code&gt;com.yourusername.myscript&lt;/code&gt;を検索します。出力結果にこの識別子が表示されれば、登録が成功していることを意味します。&lt;/p&gt;&#10;&lt;p&gt;何らかの理由で.plistファイルの登録を解除したい場合は、以下のコマンドを使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl unload ~/Library/LaunchAgents/com.yourusername.myscript.plist&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、&lt;code&gt;com.yourusername.myscript.plist&lt;/code&gt;ファイルの登録を解除し、以降のMacの起動時にはスクリプトが実行されなくなります。&lt;/p&gt;&#10;&lt;p&gt;以下は注意点です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;launchctl load&lt;/code&gt;コマンドは、Macが起動するたびに自動的にスクリプトを実行するように設定します。&lt;/li&gt;&#10;&lt;li&gt;登録を解除する際は、同じ.plistファイルを指定する必要があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事では、Macの&lt;code&gt;launchd&lt;/code&gt;システムを利用して、特定のスクリプトを起動時に自動的に実行する方法について詳しく説明しました。スクリプトの準備から、.plistファイルの作成、そして&lt;code&gt;launchd&lt;/code&gt;による登録までの全ステップをカバーしました。また、引数を含むスクリプトの扱い方についても触れました。&lt;/p&gt;&#10;</description></item><item><title>AWS AppSync + DynamoDB（複合キーテーブル）の自動生成されたリゾルバによるアイテム削除が失敗した時の対応</title><link>https://ai.hack-le.com/aws-appsync-dynamodb/</link><pubDate>Fri, 24 Nov 2023 00:02:18 +0900</pubDate><guid>https://ai.hack-le.com/aws-appsync-dynamodb/</guid><description>&lt;p&gt;端的に言うと、AppSync + DynamoDBで自動生成されたリゾルバを使ってデータ削除しようとしたら、次のエラーが出た時の対応です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;The variables input contains a field that is not defined for input object type &amp;#39;DeleteHogeHoge&amp;#39; &amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;結論的には、DynamoDBのソートキーが無視されたリゾルバになっていました。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS Amplifyは、Webおよびモバイルアプリケーションの開発を迅速化するためのツールセットです。Amplifyを使用すると、認証、データストレージ、APIなどの機能を簡単に実装できます。特に、GraphQL APIの作成とデプロイに関しては、AWS AppSyncが強力な支援を提供します。&lt;/p&gt;&#10;&lt;p&gt;AWS AppSyncは、開発者が効率的にGraphQL APIを構築し、管理できるように設計されたフルマネージドサービスです。AppSyncは、データのリアルタイム同期やオフラインデータアクセスなど、複雑なデータ操作を簡単に処理できることで知られています。&lt;/p&gt;&#10;&lt;p&gt;しかし、これらのツールは自動化されたプロセスに頼っているため、特定のデータモデルやユースケースに対する細かいカスタマイズが必要な場合、問題が生じることがあります。私が直面した問題は、AWS Amplifyが提供する自動コード生成機能と、DynamoDBの複合プライマリキーを使用したテーブル設計の間の整合性に関するものでした。&lt;/p&gt;&#10;&lt;h2 id="appsyncとdynamodbの基本"&gt;AppSyncとDynamoDBの基本&#10;&lt;/h2&gt;&lt;p&gt;AWS AppSyncとDynamoDBは、AWSエコシステムの中で重要な位置を占めています。これらのサービスを理解することは、モダンなクラウドベースのアプリケーション開発において不可欠です。&lt;/p&gt;&#10;&lt;h3 id="aws-appsync"&gt;AWS AppSync&#10;&lt;/h3&gt;&lt;p&gt;AWS AppSyncは、データ駆動型のアプリケーションにおいてリアルタイムのデータ同期と通信を容易にするマネージドGraphQLサービスです。AppSyncを使用すると、フロントエンド開発者はバックエンドの複雑さを意識せずに、必要なデータを簡単に取得、変更、購読することができます。&lt;/p&gt;&#10;&lt;p&gt;GraphQLスキーマを定義することで、AppSyncはそのスキーマに基づいてAPIを生成します。例えば、本のデータモデルに対する簡単なGraphQLスキーマは次のようになります：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;getBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;listBooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Mutation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BookInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deleteBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="dynamodb"&gt;DynamoDB&#10;&lt;/h3&gt;&lt;p&gt;DynamoDBは、高速かつ柔軟なNoSQLデータベースサービスで、キー-バリューおよびドキュメントデータモデルをサポートしています。DynamoDBは、パーティションキーとソートキーを組み合わせた複合プライマリキーを使ってデータをユニークに識別します。&lt;/p&gt;&#10;&lt;p&gt;例えば、本の情報を格納するDynamoDBテーブルの設計は次のようになります：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;TableName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Books&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;KeySchema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AttributeName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;KeyType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;HASH&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;パーティションキー&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AttributeName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;book_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;KeyType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;RANGE&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;ソートキー&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここでの問題は、AppSyncが自動的に生成するリゾルバがこの複合キー構造を正しく扱っていないことでした。次のセクションでは、この問題がどのように発生し、どのようにしてそれに気づいたのかを詳しく説明します。&lt;/p&gt;&#10;&lt;h2 id="問題の発生"&gt;問題の発生&#10;&lt;/h2&gt;&lt;p&gt;プロジェクトの進行中に、AWS AppSyncとDynamoDBを使用してデータの保存と取得を行っていましたが、特定の操作で予期せぬ問題に直面しました。&lt;/p&gt;&#10;&lt;h3 id="自動生成されたリゾルバの問題"&gt;自動生成されたリゾルバの問題&#10;&lt;/h3&gt;&lt;p&gt;AWS AppSyncは、GraphQLスキーマに基づいてAPIを生成し、さらにDynamoDBテーブルとの間でデータを操作するためのリゾルバを自動生成します。私のプロジェクトでは、&lt;code&gt;user_id&lt;/code&gt; と &lt;code&gt;book_id&lt;/code&gt; を複合キーとするDynamoDBテーブルを用意していました。通常、このようなテーブル設計では、両方のキーを使用してデータを操作することが期待されます。&lt;/p&gt;&#10;&lt;p&gt;しかし、AppSyncが生成した削除操作のリゾルバは、&lt;code&gt;book_id&lt;/code&gt; を無視し、&lt;code&gt;user_id&lt;/code&gt; のみを使用してデータを削除しようとしていました。このため、期待通りにデータを削除できず、エラーが発生していました。&lt;/p&gt;&#10;&lt;h3 id="コードによる問題の特定"&gt;コードによる問題の特定&#10;&lt;/h3&gt;&lt;p&gt;この問題に気づいたのは、削除操作を試行した際にエラーが発生し、データが削除されなかったことからでした。エラーメッセージを解析した結果、DynamoDBからのレスポンスが「提供されたキーエレメントがスキーマと一致しない」という内容であることを突き止めました。&lt;/p&gt;&#10;&lt;p&gt;AWS AppSyncのコンソールにアクセスし、リゾルバのコードを確認したところ、自動生成されたリゾルバが以下のようになっていることがわかりました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;Deletes&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;user_Id&lt;/span&gt; &lt;span class="sb"&gt;`ctx.args.input.user_Id`&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;DynamoDB&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;DynamoDBDeleteItemRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DeleteItem&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toMapValues&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このリゾルバは、&lt;code&gt;book_id&lt;/code&gt; を考慮せずに &lt;code&gt;user_id&lt;/code&gt; のみを使用しているため、複合キーを持つテーブルで適切な削除操作を行うことができませんでした。&lt;/p&gt;&#10;&lt;p&gt;次のセクションでは、この問題をどのように分析し、解決策をどのように導き出したかを詳しく説明します。&lt;/p&gt;&#10;&lt;p&gt;もちろんです。以下は、「問題の解析と解決策」セクションの詳細な文章です。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="問題の解析と解決策"&gt;問題の解析と解決策&#10;&lt;/h2&gt;&lt;h3 id="問題の根本的な原因"&gt;問題の根本的な原因&#10;&lt;/h3&gt;&lt;p&gt;エラーメッセージの分析から、問題の根本原因がAppSyncの自動生成リゾルバにあることが明らかになりました。AppSyncは、スキーマ定義に基づいて削除操作のリゾルバを生成する際、DynamoDBテーブルの複合キー（&lt;code&gt;user_id&lt;/code&gt; と &lt;code&gt;book_id&lt;/code&gt;）を正しく扱っていませんでした。リゾルバは &lt;code&gt;user_id&lt;/code&gt; のみを使用して削除を試み、&lt;code&gt;book_id&lt;/code&gt; を完全に無視していました。&lt;/p&gt;&#10;&lt;h3 id="リゾルバの手動修正"&gt;リゾルバの手動修正&#10;&lt;/h3&gt;&lt;p&gt;この問題に対処するためには、リゾルバを手動で修正し、DynamoDBのテーブルキー構造に合わせる必要がありました。具体的には、リゾルバのリクエストマッピングテンプレートを次のように更新しました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;Deletes&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;user_Id&lt;/span&gt; &lt;span class="sb"&gt;`ctx.args.input.user_Id`&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;DynamoDB&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;DynamoDBDeleteItemRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book_id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DeleteItem&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toMapValues&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book_id&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この修正により、リゾルバは &lt;code&gt;user_id&lt;/code&gt; と &lt;code&gt;book_id&lt;/code&gt; の両方を使用して削除操作を実行するようになり、DynamoDBのテーブルキー構造に適切に合わせられました。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事を通じて、AWS AmplifyとAppSyncを利用する際に直面する可能性のある一つの典型的な問題とその解決策を共有しました。自動生成されたリゾルバがDynamoDBの複合キー構造を正しく扱わない場合の対処法と、その過程で得られた学びを詳しく説明しました。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;AWS AppSyncの自動生成リゾルバは、複雑なキースキーマを持つDynamoDBテーブルに対して常に適切ではない。&lt;/li&gt;&#10;&lt;li&gt;データモデルや要件に応じてリゾルバを手動で検証し、調整することが重要。&lt;/li&gt;&#10;&lt;li&gt;基礎となるAWSサービスの動作と制約を理解することが、問題解決に不可欠。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;AWS AmplifyとAppSyncは強力なツールですが、それらを最大限に活用するには、サービスの内部動作に対する深い理解が必要です。&lt;/p&gt;&#10;&lt;h2 id="参考"&gt;参考&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.amplify.aws/javascript/build-a-backend/graphqlapi/" target="_blank" rel="noopener"&#10; &gt;API (GraphQL) - JavaScript - AWS Amplify Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>WordPressでユーザープロフィールを更新すると403が出る問題</title><link>https://ai.hack-le.com/wordpress-403/</link><pubDate>Sun, 19 Nov 2023 22:22:39 +0900</pubDate><guid>https://ai.hack-le.com/wordpress-403/</guid><description>&lt;h2 id="イントロダクション"&gt;イントロダクション&#10;&lt;/h2&gt;&lt;p&gt;WordPressは、柔軟性と使いやすさで知られる世界最大のコンテンツ管理システムです。しかし、時には技術的な障害に直面することもあります。最近、私はWordPressのユーザープロフィールを更新しようとした際に、403エラーに遭遇しました。これはアクセス拒否エラーであり、サイトの管理者である私にとっては驚きでした。なぜなら、管理者にはサイトの全ての部分へのアクセス権限があるはずだからです。&lt;/p&gt;&#10;&lt;p&gt;この経験をきっかけに、レンタルサーバー上のWordPressサイトで発生するこの種の問題について調査を始めました。多くのユーザーが同様の問題に直面していることが分かり、その原因と解決策を探る過程が非常に興味深いものでした。この記事では、私が経験した問題の原因と、それを解決するために踏んだステップについて共有します。特に、WebアプリケーションファイアウォールであるModSecurityの役割に焦点を当て、レンタルサーバーでのWordPress管理におけるその重要性と複雑さを探ります。&lt;/p&gt;&#10;&lt;h2 id="問題の特定"&gt;問題の特定&#10;&lt;/h2&gt;&lt;p&gt;管理者である私がサイトの特定の部分へのアクセスを拒否されるのは、明らかに異常な状況です。この問題の根本的な原因は、ModSecurityにありました。ModSecurityの機能をオフにすることで、ユーザープロフィールの更新が成功するようになりました。どうやら、ModSecurityは、特定のリクエストパターンを不正な攻撃と誤認識し、それに反応してアクセスをブロックしていたようです。これは、ModSecurityのルールが厳格すぎるか、または特定のWordPress操作との間で予期せぬ衝突が発生していることを示唆しています。&lt;/p&gt;&#10;&lt;p&gt;このような状況を「誤検知」と呼びます。誤検知は、セキュリティメカニズムが本来の目的である保護を超え、正当なユーザーアクションまで妨害してしまうケースです。この問題を解決するためには、ModSecurityの設定を見直す必要がありますが、レンタルサーバーの一般ユーザーには、通常、これらの設定への直接的なアクセス権限がありません。&lt;/p&gt;&#10;&lt;h2 id="modsecurityとは何か"&gt;ModSecurityとは何か&#10;&lt;/h2&gt;&lt;p&gt;さて、ModSecurityとはなんでしょうか。Webの世界では、セキュリティは常に最優先事項です。ここで重要な役割を果たすのが、ModSecurityです。ModSecurityは、オープンソースのWebアプリケーションファイアウォール（WAF）であり、Webサイトをさまざまなオンラインの脅威から保護するために広く使用されています。これは、クロスサイトスクリプティング（XSS）、SQLインジェクション、およびその他の悪意のあるデータ送信試みなど、多くの一般的なWebベースの攻撃をブロックします。&lt;/p&gt;&#10;&lt;p&gt;ModSecurityの主な機能は、Webサーバーへの要求をリアルタイムで監視し、特定のルールに基づいてその内容を分析することです。不正行為や異常な活動が検出された場合、ModSecurityはそれをブロックし、サイトの安全を確保します。Apache、Nginx、IISなどの主要なWebサーバーで動作し、cPanelを含む多くのホスティングプラットフォームで利用できるため、幅広いユーザーに対応しています。&lt;/p&gt;&#10;&lt;p&gt;しかし、この強力なセキュリティ機能は、時に誤って正当なリクエストをブロックすることがあります。これを「誤検知（False Positive）」と呼び、セキュリティシステムが誤って正規の活動を不正な活動と見なす現象です。WordPressなどの一般的なコンテンツ管理システムを使用している場合、ModSecurityのデフォルト設定がプラグインや特定の管理機能と衝突することがあります。&lt;/p&gt;&#10;&lt;h2 id="対応cpanelでのmodsecurityの管理"&gt;対応：cPanelでのModSecurityの管理&#10;&lt;/h2&gt;&lt;p&gt;cPanelは、Webホスティングアカウントを管理するための直感的なインターフェースを提供します。ModSecurityの管理も、cPanelを通じて簡単に行うことができますが、その設定は基本的に「オン/オフ」の切り替えに限られています。これは、多くのユーザーにとっては便利ですが、特定の誤検知問題に対処するには限界があります。&lt;/p&gt;&#10;&lt;p&gt;cPanel内でModSecurityを無効にすることは、一時的な解決策として有効です。しかし、これはあくまで一時的な対処であり、本質的な解決には至りません。ModSecurityを無効にすることは、Webサイトをさまざまなオンライン脅威から守る重要な防御層を失うことを意味します。したがって、このオプションを選択する際は、最小限の時間だけ無効にし、問題が解決したらすぐに再度有効にすることが重要です。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;ModSecurityは、ウェブサイトの安全を守るために不可欠なツールです。その一方で、誤検知による問題が発生することもあります。このような場合、一時的にModSecurityを無効にすることが解決策となることがありますが、このアプローチには注意が必要です。&lt;/p&gt;&#10;&lt;p&gt;最終的には、以下のベストプラクティスを心掛けることが重要です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;ModSecurityの再有効化&lt;/strong&gt;：一時的な対応が完了したら、速やかにModSecurityを再有効化してください。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ホスティングプロバイダーとの連携&lt;/strong&gt;：問題が継続する場合、ホスティングプロバイダーに相談し、より根本的な解決策を模索することをお勧めします。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="参考"&gt;参考&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://zakkipost.com/wordpress/wordpress-profile-403error" target="_blank" rel="noopener"&#10; &gt;【Wordpress】プロフィールが更新できない（403エラー）場合の対処方法 – MixHost – ZAKKIPOST&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>DynamoDBで小数点(float)を扱う: PythonでFloatをDecimalに変換する</title><link>https://ai.hack-le.com/dynamodb-float-python-decimal/</link><pubDate>Wed, 15 Nov 2023 18:51:17 +0900</pubDate><guid>https://ai.hack-le.com/dynamodb-float-python-decimal/</guid><description>&lt;h2 id="dynamodbで小数点を扱う時の注意"&gt;DynamoDBで小数点を扱う時の注意&#10;&lt;/h2&gt;&lt;p&gt;Amazon DynamoDBは、高速で柔軟性があり、スケーラブルなNoSQLデータベースサービスとして広く利用されています。このサービスは、大規模なデータセットを迅速に処理し、簡単にアクセスする能力で知られており、ウェブスケールアプリケーションからビッグデータ分析まで、幅広い用途に適しています。しかし、DynamoDBを最大限に活用するには、そのデータ型の特性を理解し、適切に扱う必要があります。&lt;/p&gt;&#10;&lt;p&gt;特に注意が必要なのは、DynamoDBにおける数値データの扱いです。DynamoDBは数値をDecimal型として保存し、この形式は浮動小数点数（float型）とは異なる特性を持っています。なぜこれが重要なのでしょうか？一般的なプログラミング言語では、数値はしばしばfloat型で扱われますが、この型は精度の問題を引き起こす可能性があります。一方、Decimal型は固定小数点数を用いることで、これらの精度の問題を回避します。この特性は、金融データの処理や、正確な数値計算が求められる場合に特に重要です。&lt;/p&gt;&#10;&lt;p&gt;このため、DynamoDBにデータを保存する際には、float値をDecimal型に変換することが不可欠です。この小さな変更が、データの整合性を維持し、予期せぬエラーや計算の不正確さを防ぐ鍵となります。本記事では、この変換プロセスを簡単に行うためのPython関数を紹介し、その実装方法と利用例について詳しく説明します。&lt;/p&gt;&#10;&lt;h2 id="解決策の提示"&gt;解決策の提示&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBでのfloat値の扱いに関する問題を解決するための鍵は、適切なデータ変換です。具体的には、float型の数値をDecimal型に変換する関数を作成し、DynamoDBに書き込むデータをこの関数で処理します。このアプローチにより、DynamoDBのデータ型の制約に適合しつつ、データの精度を維持することができます。&lt;/p&gt;&#10;&lt;h3 id="decimal変換関数"&gt;Decimal変換関数&#10;&lt;/h3&gt;&lt;p&gt;この変換を行うためのPython関数は、以下のように定義できます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Recursively converts all float values in a dictionary or list to Decimals,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; which is required for DynamoDB compatibility.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この関数は、辞書やリストに含まれるfloat値を再帰的に探索し、それらをDecimal型に変換します。Pythonの&lt;code&gt;Decimal&lt;/code&gt;クラスは、float型の数値を正確な固定小数点数として表現するため、DynamoDBとの互換性が確保されます。&lt;/p&gt;&#10;&lt;h3 id="関数の動作原理"&gt;関数の動作原理&#10;&lt;/h3&gt;&lt;p&gt;この関数は、入力されたデータ構造を再帰的に探索します。辞書の場合、すべてのキーと値のペアに対してこの関数を適用し、リストの場合はリスト内の各要素に対して適用します。float型の値が見つかると、それを&lt;code&gt;Decimal&lt;/code&gt;型に変換し、他のデータ型はそのまま返します。&lt;/p&gt;&#10;&lt;p&gt;この方法により、辞書やリスト内の任意の深さにあるfloat値を確実にDecimalに変換することができます。これは特に、ネストされたデータ構造を扱う際に有効です。&lt;/p&gt;&#10;&lt;h2 id="関数の使用例"&gt;関数の使用例&#10;&lt;/h2&gt;&lt;p&gt;前のセクションで紹介した&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数は、実際のデータ変換プロセスでどのように役立つのでしょうか？ここでは、具体的な使用例を通して、この関数の実用性を示します。&lt;/p&gt;&#10;&lt;h3 id="使用例辞書の変換"&gt;使用例：辞書の変換&#10;&lt;/h3&gt;&lt;p&gt;考えられる一般的なシナリオとして、辞書にfloat値が含まれる場合があります。例えば、次のような辞書があるとします：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;example_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;3.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;6.78&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nested_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;9.01&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この辞書をDynamoDBに保存する前に、float値をDecimalに変換する必要があります。&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数を使用すると、以下のように変換できます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;converted_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;結果は次の通りです：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;key1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1.23&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;key2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3.45&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6.78&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;key3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nested_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9.01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この変換により、元の辞書内のすべてのfloat値がDecimal型に変更され、DynamoDBへの書き込みが可能になります。&lt;/p&gt;&#10;&lt;h3 id="使用例ネストされたリストと辞書"&gt;使用例：ネストされたリストと辞書&#10;&lt;/h3&gt;&lt;p&gt;この関数は、より複雑なネストされたデータ構造にも対応しています。例えば、辞書の中にリストがあり、そのリストの中にさらに辞書があるような構造に対しても、すべてのfloat値を適切にDecimalに変換します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;complex_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner_key1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;inner_key2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.67&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mf"&gt;3.21&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nested_list&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;deep_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.56&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;converted_complex_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complex_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この関数を使用することで、どのように深くネストされたデータ構造であっても、float値を正確にDecimalに変換することが可能です。&lt;/p&gt;&#10;&lt;h2 id="ベストプラクティスと考慮事項"&gt;ベストプラクティスと考慮事項&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数を使用する際には、いくつかのベストプラクティスと考慮事項を心に留めておくことが重要です。&lt;/p&gt;&#10;&lt;h3 id="データ型の確認"&gt;データ型の確認&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;入力データの確認：&lt;/strong&gt; 関数に渡す前に、入力データが辞書やリスト形式であることを確認してください。これは関数がこれらのデータ型のみを対象としているためです。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;他のデータ型との互換性：&lt;/strong&gt; 関数はfloat型以外のデータ型をそのまま返しますが、DynamoDBに保存する前に他のデータ型に対する検証も検討してください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="性能の考慮"&gt;性能の考慮&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;大規模データの取り扱い：&lt;/strong&gt; 非常に大きなデータセットや深くネストされたデータ構造を扱う際は、性能への影響を考慮する必要があります。関数の再帰的な性質は、特に大規模なデータ構造で処理時間が長くなる可能性があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="エラーハンドリング"&gt;エラーハンドリング&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;エラーハンドリングの実装：&lt;/strong&gt; 関数を組み込む際には、不適切なデータ型や予期しない入力に対するエラーハンドリングを考慮することが重要です。これにより、データ変換プロセスの堅牢性が向上します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="dynamodbとの統合"&gt;DynamoDBとの統合&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;DynamoDBとの連携：&lt;/strong&gt; この関数はDynamoDBへのデータ書き込みの一部として組み込むことが最も効果的です。データをDynamoDBに保存する前の最終段階でこの関数を使用することで、データの整合性を保つことができます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事では、DynamoDBでfloat値を効率的かつ正確に扱うための方法を紹介しました。Pythonでの&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数の実装と使用方法を通じて、DynamoDBのデータ型の制約に対応しつつ、数値データの精度を維持する方法を学びました。適切なデータ変換プロセスを実施することで、アプリケーションのデータ整合性を向上させ、DynamoDBの利用を最大化することができます。&lt;/p&gt;&#10;&lt;p&gt;了解しました。最後に「参考文献とリソース」のセクションを含めて、記事を締めくくります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="参考文献とリソース"&gt;参考文献とリソース&#10;&lt;/h2&gt;&lt;p&gt;この記事で紹介した内容の理解を深めるために、以下のリソースが役立つでしょう：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Amazon DynamoDB 公式ドキュメント：&lt;/strong&gt; DynamoDBの基本的な概念、データ型、およびベストプラクティスに関する公式ガイドは、このデータベースサービスを理解するのに最適な出発点です。&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html" target="_blank" rel="noopener"&#10; &gt;Amazon DynamoDB Developer Guide&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Pythonの&lt;code&gt;decimal&lt;/code&gt;モジュール：&lt;/strong&gt; PythonのDecimalクラスに関する公式ドキュメントを参照して、数値の精度と表現についての理解を深めることができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.python.org/3/library/decimal.html" target="_blank" rel="noopener"&#10; &gt;Python &lt;code&gt;decimal&lt;/code&gt; Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;これらのリソースは、DynamoDBの利用とデータ変換のスキルを向上させるための貴重な情報源です。この記事で紹介した関数と併用することで、DynamoDBのポテンシャルを最大限に活用し、アプリケーションのデータ処理能力を高めることができます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;この記事では、DynamoDBでのfloat値の扱いとその解決策に焦点を当て、具体的なPython関数の実装と使用方法を通じて、この問題に対処する方法を提供しました。これらの知識を活用して、自身のプロジェクトでより効果的にDynamoDBを使用してください。&lt;/p&gt;&#10;</description></item><item><title>Gitの”Executable … not executable”エラー: 原因と解決法</title><link>https://ai.hack-le.com/git-executable-xxx-not-executable/</link><pubDate>Wed, 15 Nov 2023 16:21:47 +0900</pubDate><guid>https://ai.hack-le.com/git-executable-xxx-not-executable/</guid><description>&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;Gitと&lt;code&gt;pre-commit&lt;/code&gt;は、現代のソフトウェア開発プロセスにおいて中心的な役割を果たしています。これらのツールを使うことで、開発の効率を高めながらもコードの品質を維持することができます。しかし、これらを日常的に使用する中で、予期しない問題に遭遇することもあります。今回の記事では、そんな一つの典型的な問題、「Executable &lt;code&gt;/path/to/your-script.sh&lt;/code&gt; is not executable」というエラーメッセージに遭遇した際の解決方法を掘り下げます。&lt;/p&gt;&#10;&lt;p&gt;この問題は、Gitリポジトリ内のスクリプトファイルに適切な実行権限が設定されているにも関わらず、&lt;code&gt;pre-commit&lt;/code&gt;フックがそのファイルを実行不可能とみなす状況を指します。それでは、このエラーがどのような状況で発生するのか、見ていきましょう&lt;/p&gt;&#10;&lt;h2 id="背景"&gt;背景&#10;&lt;/h2&gt;&lt;h3 id="gitとpre-commitの基本"&gt;Gitと&lt;code&gt;pre-commit&lt;/code&gt;の基本&#10;&lt;/h3&gt;&lt;p&gt;Gitは、ソースコードのバージョン管理に広く使用されているシステムです。それに対して&lt;code&gt;pre-commit&lt;/code&gt;は、Gitのコミットプロセスにフック（カスタムスクリプト）を組み込むためのツールで、コードの品質を確保するための自動化されたチェックを提供します。これらのフックは、コードがリポジトリにコミットされる前に様々なタイプの検証を行います。&lt;/p&gt;&#10;&lt;h3 id="実行権限の重要性"&gt;実行権限の重要性&#10;&lt;/h3&gt;&lt;p&gt;UNIX系オペレーティングシステム（LinuxやmacOSを含む）では、ファイルの実行権限は非常に重要です。スクリプトやプログラムが実行されるためには、適切な実行権限が設定されている必要があります。この権限は、ファイルシステム上で&lt;code&gt;chmod&lt;/code&gt;コマンドを使って設定されます。&lt;/p&gt;&#10;&lt;h3 id="gitの実行権限の取り扱い"&gt;Gitの実行権限の取り扱い&#10;&lt;/h3&gt;&lt;p&gt;Gitは、ファイルの内容と共に、その実行権限の状態も追跡します。しかし、Gitのインデックス（ステージングエリア）とローカルファイルシステムの間で実行権限の状態に不一致が生じることがあります。特に、異なる環境やファイルシステム間でGitリポジトリが共有される場合、この問題はより複雑になることがあります。&lt;/p&gt;&#10;&lt;h3 id="問題の全体像"&gt;問題の全体像&#10;&lt;/h3&gt;&lt;p&gt;この背景において、&lt;code&gt;Executable not executable&lt;/code&gt;というエラーメッセージは、Gitがスクリプトファイルの実行権限を正しく認識していない場合に発生します。これは、&lt;code&gt;pre-commit&lt;/code&gt; などのツールがスクリプトを実行しようとした際に特に顕著になります。この問題を解決するためには、Gitのインデックスとローカルファイルシステムの間の実行権限の状態を同期させる必要があります。&lt;/p&gt;&#10;&lt;h2 id="問題の詳細"&gt;問題の詳細&#10;&lt;/h2&gt;&lt;p&gt;開発者として、私たちは頻繁にコードの品質を確保し、バグを未然に防ぐために&lt;code&gt;pre-commit&lt;/code&gt;フックを利用します。ある日、私は自分のプロジェクトにカスタムの&lt;code&gt;pre-commit&lt;/code&gt;フックを追加しようとしました。このフックは、コミットメッセージが特定のフォーマットに従っているかどうかをチェックするものでした。&lt;/p&gt;&#10;&lt;p&gt;しかし、このフックを追加した後、コミットしようとすると次のようなエラーメッセージが表示されました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Executable `/path/to/your-script.sh` is not executable&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このエラーメッセージは、私のスクリプトが実行不可能とみなされていることを示していました。しかし、ファイルには明らかに実行権限が与えられていました。これは、特に混乱を招く問題でした。&lt;/p&gt;&#10;&lt;h2 id="最初のトラブルシューティングの試み"&gt;最初のトラブルシューティングの試み&#10;&lt;/h2&gt;&lt;p&gt;問題の解決に取り組むため、まずは基本的なトラブルシューティングから始めました。最初のステップとして、スクリプトファイルの実行権限を確認しました。ターミナルで以下のコマンドを実行しました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -l /path/to/your-script.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;結果は、ファイルが実行権限を持っていることを示していました（&lt;code&gt;-rwxr-xr-x&lt;/code&gt;）。次に、Gitの&lt;code&gt;core.fileMode&lt;/code&gt;設定がファイルの実行権限を正しく追跡しているかどうかを確認しました。この設定は、Gitがファイルの実行権限の変更を検出するかどうかを決定します。&lt;/p&gt;&#10;&lt;p&gt;しかし、これらの基本的なチェックにも関わらず、問題は解決しませんでした。ファイルには明らかに実行権限が付与されているにもかかわらず、&lt;code&gt;pre-commit&lt;/code&gt;は依然としてスクリプトを実行不可能と認識していました。この時点で、問題がもう少し複雑なものであることが明らかになりました。&lt;/p&gt;&#10;&lt;h2 id="解決策git-update-index---chmodx"&gt;解決策：&lt;code&gt;git update-index --chmod=+x&lt;/code&gt;&#10;&lt;/h2&gt;&lt;p&gt;最初のトラブルシューティングのステップが効果を示さなかった後、さらに深く問題を掘り下げました。調査の結果、Gitのインデックスとファイルシステムの間で実行権限の状態に不一致が生じている可能性が浮上しました。この不一致を解消するために、&lt;code&gt;git update-index --chmod=+x&lt;/code&gt; コマンドを使用することにしました。&lt;/p&gt;&#10;&lt;p&gt;このコマンドは、Gitに対して特定のファイルに実行権限があることを明示的に指示します。コマンドを実行することで、Gitのインデックスが更新され、ファイルが実行可能として認識されるようになります。以下のコマンドを実行しました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git update-index --chmod&lt;span class="o"&gt;=&lt;/span&gt;+x /path/to/your-script.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを実行した後、再びコミットを試みると、今度は成功しました。エラーメッセージは消え、&lt;code&gt;pre-commit&lt;/code&gt; フックが正常に実行されました。&lt;/p&gt;&#10;&lt;h2 id="なぜこのコマンドが効果的だったのか"&gt;なぜこのコマンドが効果的だったのか&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;git update-index --chmod=+x&lt;/code&gt; コマンドが効果的だった理由は、Gitのインデックスがローカルのファイルシステムの状態と同期していなかったためです。通常、Gitはファイルの内容とメタデータ（この場合は実行権限）を追跡しますが、特定の状況下ではこれらの情報が不一致になることがあります。このコマンドによって、Gitの内部状態が強制的に更新され、スクリプトが実行可能であるという情報がGitのインデックスに正しく反映されました。&lt;/p&gt;&#10;&lt;p&gt;この経験から、特に複数の環境やファイルシステムを跨いで作業する場合には、Gitのインデックスとローカルのファイルシステムの間で生じる可能性のある不一致に注意が必要であることがわかりました。&lt;/p&gt;&#10;&lt;h2 id="他の関連する問題への適用"&gt;他の関連する問題への適用&#10;&lt;/h2&gt;&lt;p&gt;この問題とその解決策は、特定の状況に限定されるものではありません。実際、異なるオペレーティングシステムやGitの設定、さらには異なるバージョンのGitを使用する際にも類似の問題が発生する可能性があります。特に、チーム内で複数の開発環境が混在している場合、Gitのインデックスとファイルシステム間の不一致は一般的な問題となり得ます。&lt;/p&gt;&#10;&lt;p&gt;また、この問題は&lt;code&gt;pre-commit&lt;/code&gt;フックに限定されず、他のGitフックやスクリプト実行の文脈でも発生する可能性があります。そのため、Gitの実行権限に関連するエラーに直面した場合は、&lt;code&gt;git update-index --chmod=+x&lt;/code&gt; コマンドの使用を検討することが有益です。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;この経験から、私たちはGitと&lt;code&gt;pre-commit&lt;/code&gt;の使用におけるいくつかの重要な教訓を学びました。最も重要なのは、Gitのインデックスとローカルのファイルシステムの間に生じる可能性のある不一致に注意を払うことです。また、標準的なトラブルシューティング手法が効果を示さない場合でも、Gitのより高度な機能やコマンドを使用して問題を解決する方法が存在することを理解することも重要です。&lt;/p&gt;&#10;&lt;p&gt;最後に、この問題は、開発者が遭遇する可能性のある一連の問題の一例に過ぎません。技術的な問題に直面した際には、根気強く原因を探求し、コミュニティやドキュメントからのサポートを活用することが不可欠です。このような経験は、技術的スキルの向上だけでなく、より良い開発者に成長するための道の一部です。&lt;/p&gt;&#10;&lt;h2 id="参考リンク"&gt;参考リンク&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/asottile" target="_blank" rel="noopener"&#10; &gt;&amp;ldquo;Executable &amp;hellip; is not executable&amp;rdquo; error · Issue #1514 · pre-commit/pre-commit&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>メタデータを含まないGitHub.comからGitHub Enterpriseへのリポジトリ移行ガイド</title><link>https://ai.hack-le.com/github-com-github-enterprise/</link><pubDate>Tue, 14 Nov 2023 13:29:37 +0900</pubDate><guid>https://ai.hack-le.com/github-com-github-enterprise/</guid><description>&lt;p&gt;&lt;strong&gt;導入&lt;/strong&gt;: GitHubからGitHub Enterpriseへのリポジトリ移行の際は、まずメタデータの移行をするかどうかが重要な判断となります。GitHubリポジトリのメタデータ（Issueやプルリクエストなど）の移行を行うかどうかを判断する際に考慮すべきポイントは以下の通りです：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;プロジェクトの歴史の重要性&lt;/strong&gt;: 過去のIssueやプルリクエストが将来のプロジェクト運営に重要な情報を含んでいる場合、これらのデータを移行する価値があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;プロジェクトの継続性&lt;/strong&gt;: 新しい環境でのプロジェクトの継続性を保つために、過去の議論や決定の履歴を参照できることが重要な場合は、メタデータの移行を検討すべきです。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;リソースと技術力&lt;/strong&gt;: メタデータの移行は複雑で時間とリソースを要するプロセスです。十分な技術力とリソースがあるかどうかを評価してください。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;プロジェクトの将来計画&lt;/strong&gt;: プロジェクトが新しいフェーズに入っており、過去のデータがそれほど関連性を持たない場合、メタデータの移行は必要ないかもしれません。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;これらの要素を総合的に検討し、プロジェクトのニーズとリソースに基づいて決定を下すことが重要です。&lt;/p&gt;&#10;&lt;p&gt;Issueやプルリクエスト（PR）などのメタデータを含まなくてよい場合、移行は比較的簡単なプロセスです。ここでは、コードとコミット履歴のみを移行する手順を詳細に説明します。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;手順&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;新しいリポジトリの作成&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;GitHub Enterpriseにログインし、新しいリポジトリを作成します。このリポジトリは空である必要があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;ローカルリポジトリの準備&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;移行するローカルリポジトリで作業している場合、最新の状態に更新しておきます（&lt;code&gt;git pull&lt;/code&gt;）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;&lt;strong&gt;リモートURLの変更&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;リポジトリのリモートURLをGitHub Enterpriseの新しいリポジトリURLに変更します。これには&lt;code&gt;git remote set-url origin [新しいURL]&lt;/code&gt;コマンドを使用します。（ &lt;code&gt;.git/config&lt;/code&gt;を参照することで変更を確認できます）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;&lt;strong&gt;コードのプッシュ&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;git push -u origin master&lt;/code&gt;（または対象のブランチ名）を使用して、コードを新しいリポジトリにプッシュします。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;チームメンバーへの指示&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;チームの他のメンバーも、自分のローカルリポジトリで同じリモートURLの変更を行う必要があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;注意点&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;この方法では、コードとコミット履歴のみが移行されます。GitHubのメタデータ（Issue、PRなど）は移行されません。これらの情報を移行したい場合は、追加の手順が必要です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;結論&lt;/strong&gt;: GitHub.comからGitHub Enterpriseへのリポジトリ移行は、上記の手順を実行することで、簡単かつ効率的に行うことができます。ただし、プロジェクトの要件に応じて、メタデータの移行も検討してください。&lt;/p&gt;&#10;</description></item><item><title>[Mac] シェルスクリプトでファイルを日付別に整理する方法</title><link>https://ai.hack-le.com/mac-shell-date-folder/</link><pubDate>Tue, 31 Oct 2023 22:34:55 +0900</pubDate><guid>https://ai.hack-le.com/mac-shell-date-folder/</guid><description>&lt;h4 id="はじめに"&gt;はじめに&#10;&lt;/h4&gt;&lt;p&gt;ファイルの整理は作業効率を上げる重要なステップです。特に、多くのファイルがあるディレクトリでは、ファイルを日付別に分類することで目的のファイルを素早く見つけられるようになります。&lt;/p&gt;&#10;&lt;p&gt;この記事では、シェルスクリプトを使用してファイルを最終変更日に基づいて日付別のフォルダに自動で移動する方法を紹介します。&lt;/p&gt;&#10;&lt;h4 id="手順"&gt;手順&#10;&lt;/h4&gt;&lt;ol&gt;&#10;&lt;li&gt;ターミナルを開き、整理したいファイルがあるディレクトリに移動します。&lt;/li&gt;&#10;&lt;li&gt;以下のシェルスクリプトを作成します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;stat -f &lt;span class="s2"&gt;&amp;#34;%Sm&amp;#34;&lt;/span&gt; -t &lt;span class="s2"&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; ! -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mkdir &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="s2"&gt;/&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;スクリプトを保存し、実行権限を与えます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x script.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;スクリプトを実行します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./script.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="まとめ"&gt;まとめ&#10;&lt;/h4&gt;&lt;p&gt;この記事では、シェルスクリプトを使用してファイルを最終変更日に基づいて日付別のフォルダに自動で分類する方法を紹介しました。簡単なスクリプトで作業効率が大幅に向上します。是非お試しください。&lt;/p&gt;&#10;</description></item><item><title>WordPressで使用されていない画像を削除する方法：Media Cleanerプラグインの使い方</title><link>https://ai.hack-le.com/wordpress-media-cleaner/</link><pubDate>Tue, 31 Oct 2023 02:59:51 +0900</pubDate><guid>https://ai.hack-le.com/wordpress-media-cleaner/</guid><description>&lt;p&gt;WordPressのサイト運営をしていると、不要な画像やメディアファイルが増えてくることがあります。そんな時に役立つのが「Media Cleaner」というプラグインです。この記事では、Media Cleanerのインストールから使用方法までを詳しく解説します。&lt;/p&gt;&#10;&lt;h4 id="1-media-cleanerとは"&gt;1. Media Cleanerとは？&#10;&lt;/h4&gt;&lt;p&gt;Media Cleanerは、WordPressのメディアライブラリやuploadsディレクトリから使用されていないメディアファイルを検出し、削除するためのプラグインです。記事、ページ、カスタムポストタイプ、ウィジェットなど、さまざまな場所でのメディアの使用状況をチェックします。&lt;/p&gt;&#10;&lt;h4 id="2-インストールと有効化"&gt;2. インストールと有効化&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;WordPressのダッシュボードから「プラグイン」&amp;gt;「新規追加」に移動。&lt;/li&gt;&#10;&lt;li&gt;「Media Cleaner」を検索し、インストール後に有効化。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="3-基本設定の方法"&gt;3. 基本設定の方法&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;ダッシュボードの左側のメニューから「メディア」&amp;gt;「Cleaner」を選択。&lt;/li&gt;&#10;&lt;li&gt;「設定」タブに移動し、スキャンの範囲やチェックの対象を設定。例えば、メディアライブラリだけでなく、テーマやウィジェットの中もチェックするかどうかを選べます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="4-使用されていないメディアの検出"&gt;4. 使用されていないメディアの検出&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;「ダッシュボード」タブに戻り、スキャンを開始。&lt;/li&gt;&#10;&lt;li&gt;スキャンが完了すると、使用されていないと検出されたメディアファイルのリストが表示。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="5-不要なメディアの削除方法"&gt;5. 不要なメディアの削除方法&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;表示されたリストを確認し、誤検出がないか手動でチェック。&lt;/li&gt;&#10;&lt;li&gt;使用されていないと確認されたメディアを選択し、「削除」ボタンをクリック。&lt;/li&gt;&#10;&lt;li&gt;必要に応じて、ゴミ箱から完全に削除するか、元に戻すことができます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="6-まとめ"&gt;6. まとめ&#10;&lt;/h4&gt;&lt;p&gt;Media Cleanerを使用することで、不要なメディアファイルを効率的に整理し、サイトの容量を節約することができます。ただし、操作には注意が必要です。特に、使用前には必ずサイトのバックアップを取ることを忘れずに！&lt;/p&gt;&#10;</description></item><item><title>MacのAutomatorクイックアクションを別のMacで共有する方法</title><link>https://ai.hack-le.com/mac-automator/</link><pubDate>Mon, 30 Oct 2023 12:37:21 +0900</pubDate><guid>https://ai.hack-le.com/mac-automator/</guid><description>&lt;p&gt;MacのAutomatorは、日常の作業を自動化するための強力なツールです。このツールを使用して作成したクイックアクションを、他のMacで共有したいと思ったことはありませんか？この記事では、その方法を簡単に説明します。&lt;/p&gt;&#10;&lt;h2 id="ステップ1-クイックアクションの保存場所を探す"&gt;ステップ1: クイックアクションの保存場所を探す&#10;&lt;/h2&gt;&lt;p&gt;Automatorで作成したクイックアクションは、通常以下のディレクトリのいずれかに保存されています。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;ユーザーごとの設定: &lt;code&gt;~/Library/Services/&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;システム全体の設定: &lt;code&gt;/Library/Services/&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;ここでの &lt;code&gt;~&lt;/code&gt; は、現在ログインしているユーザーのホームディレクトリを指します。&lt;/p&gt;&#10;&lt;h2 id="ステップ2-クイックアクションのファイルをコピー"&gt;ステップ2: クイックアクションのファイルをコピー&#10;&lt;/h2&gt;&lt;p&gt;クイックアクションのファイルは &lt;code&gt;.workflow&lt;/code&gt; 拡張子を持っています。これを右クリックし、「コピー」を選択するか、ドラッグしてデスクトップなど別の場所にコピーします。&lt;/p&gt;&#10;&lt;h2 id="ステップ3-ファイルを別のmacに転送"&gt;ステップ3: ファイルを別のMacに転送&#10;&lt;/h2&gt;&lt;p&gt;コピーした &lt;code&gt;.workflow&lt;/code&gt; ファイルを、AirDrop、USBドライブ、Dropboxによる共有、メール添付ファイルなどを使用して別のMacに転送します。&lt;/p&gt;&#10;&lt;h2 id="ステップ4-クイックアクションをインストール"&gt;ステップ4: クイックアクションをインストール&#10;&lt;/h2&gt;&lt;p&gt;転送したファイルを受け取ったMacで、ファイルを右クリックし、「コピー」を選択します。その後、ステップ1で確認したディレクトリ（&lt;code&gt;~/Library/Services/&lt;/code&gt; または &lt;code&gt;/Library/Services/&lt;/code&gt;）に移動し、「ペースト」を選択してファイルをコピーします。&lt;/p&gt;&#10;&lt;h2 id="ステップ5-クイックアクションを有効にする"&gt;ステップ5: クイックアクションを有効にする&#10;&lt;/h2&gt;&lt;p&gt;システム環境設定を開き、「キーボード」セクションの「ショートカット」タブをクリックします。左側のリストから「サービス」を選択し、右側のリストで新しくインストールしたクイックアクションを探してチェックマークをつけ、必要に応じてショートカットを設定します。&lt;/p&gt;&#10;&lt;p&gt;これで、新しいMacでも元のクイックアクションを使用することができるようになりました。Automatorのクイックアクションを共有することで、より効率的に作業を進めることができます。&lt;/p&gt;&#10;</description></item><item><title>AWS Systems Manager パラメータストアから Python で値を取得する方法</title><link>https://ai.hack-le.com/aws-systems-manager-python/</link><pubDate>Sun, 29 Oct 2023 02:49:11 +0900</pubDate><guid>https://ai.hack-le.com/aws-systems-manager-python/</guid><description>&lt;p&gt;AWS Systems Manager のパラメータストアは、データベースの接続文字列やパスワードなどの設定情報をセキュアに保存して管理するためのサービスです。この記事では、ローカルの Python スクリプトを使ってパラメータストアに保存されている値を取得する方法を説明します。&lt;/p&gt;&#10;&lt;h3 id="1-必要なライブラリをインストール"&gt;1. 必要なライブラリをインストール&#10;&lt;/h3&gt;&lt;p&gt;まず、AWS SDK for Python (Boto3) をインストールします。これをインストールするために、以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-python-スクリプトを作成"&gt;2. Python スクリプトを作成&#10;&lt;/h3&gt;&lt;p&gt;以下のサンプルコードを使用して、パラメータストアから任意のパラメータ名で保存されている値を取得します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_parameter_from_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Boto3 クライアントを初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ssm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ssm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# パラメータを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# 暗号化されている場合はデコード&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# パラメータの値を返す&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Parameter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;param_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Enter the parameter name: &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;param_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_parameter_from_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Value of &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;param_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-aws-認証情報を設定"&gt;3. AWS 認証情報を設定&#10;&lt;/h3&gt;&lt;p&gt;ローカルマシンに &lt;code&gt;~/.aws/credentials&lt;/code&gt; というファイルを作成し、以下の内容を追加します。これにより、Boto3 は自動的にこのファイルの認証情報を使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[default]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_access_key_id = YOUR_ACCESS_KEY_ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_secret_access_key = YOUR_SECRET_ACCESS_KEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: 実際のアクセスキーとシークレットアクセスキーに置き換えてください。&lt;/p&gt;&#10;&lt;h3 id="4-python-スクリプトを実行"&gt;4. Python スクリプトを実行&#10;&lt;/h3&gt;&lt;p&gt;上記のスクリプトを保存し、ローカルマシンで実行します。スクリプトを実行すると、取得したいパラメータ名を入力するプロンプトが表示されるので、対応する名前を入力してください。これにより、指定したパラメータの値がコンソールに表示されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;これで、AWS Systems Manager のパラメータストアからローカルの Python スクリプトで値を読み取る方法についての概要を把握することができました。&lt;/p&gt;&#10;</description></item><item><title>Fishスクリプトでファイル名に日付時刻を追加する</title><link>https://ai.hack-le.com/fish-file-timestamp/</link><pubDate>Fri, 29 Sep 2023 07:52:46 +0900</pubDate><guid>https://ai.hack-le.com/fish-file-timestamp/</guid><description>&lt;p&gt;Fishシェルは、その美しいシンタックスと強力な機能で知られています。この記事では、Fishスクリプトを使用してカレントディレクトリの各ファイル名にタイムスタンプ（ここでは日付と時刻の文字列）を追加する方法を紹介します。このスクリプトは、既にタイムスタンプが付いているファイルは無視するので、複数回実行しても安全です。また、ディレクトリは対象外です。&lt;/p&gt;&#10;&lt;p&gt;以下に、タイムスタンプを追加するためのスクリプトを示します。&lt;/p&gt;&#10;&lt;p&gt;ワンライナースクリプト:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -f &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; and not string match -r &lt;span class="s2"&gt;&amp;#34;^[0-9]{14}_&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; timestamp &lt;span class="o"&gt;(&lt;/span&gt;date -r &lt;span class="nv"&gt;$file&lt;/span&gt; +&lt;span class="s2"&gt;&amp;#34;%Y%m%d%H%M%S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; mv &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;_&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; end&lt;span class="p"&gt;;&lt;/span&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分割バージョン:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -f &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; and not string match -r &lt;span class="s2"&gt;&amp;#34;^[0-9]{14}_&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &amp;gt; /dev/null&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;set&lt;/span&gt; timestamp &lt;span class="o"&gt;(&lt;/span&gt;date -r &lt;span class="nv"&gt;$file&lt;/span&gt; +&lt;span class="s2"&gt;&amp;#34;%Y%m%d%H%M%S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;_&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;bashバージョン:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; -f &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; ! &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;]{&lt;/span&gt;14&lt;span class="o"&gt;}&lt;/span&gt;_ &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date -r &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; +&lt;span class="s2"&gt;&amp;#34;%Y%m%d%H%M%S&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらのスクリプトは、カレントディレクトリの全てのファイルをループし、各ファイルに対して以下の操作を行います&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;test -f&lt;/code&gt;コマンドを使用して、アイテムがファイルであることを確認します（ディレクトリは除外されます）。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;string match&lt;/code&gt;コマンドを使用して、ファイル名が既にタイムスタンプを含んでいるかどうかを確認します。&lt;/li&gt;&#10;&lt;li&gt;タイムスタンプが含まれていない場合、&lt;code&gt;date&lt;/code&gt;コマンドを使用してファイルのタイムスタンプを生成します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;mv&lt;/code&gt;コマンドを使用して、生成されたタイムスタンプとアンダースコアをファイル名の先頭に追加し、ファイル名を変更します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;このスクリプトは、ファイルの整理と管理を容易にし、ファイルのバージョン管理を簡単に行えるようにします。&lt;/p&gt;&#10;</description></item><item><title>AWS CloudWatch Logs Insightsで特定のイベントが起きた回数をbin()関数で時間ごとにカウントする</title><link>https://ai.hack-le.com/aws-cloudwatch-logs-insights-bin/</link><pubDate>Mon, 25 Sep 2023 18:10:47 +0900</pubDate><guid>https://ai.hack-le.com/aws-cloudwatch-logs-insights-bin/</guid><description>&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS CloudWatch Logs Insightsは、ログデータを効率的に探索・分析するためのさまざまな機能と能力を提供しています。その中でも特に強力な関数の一つが&lt;code&gt;bin()&lt;/code&gt;で、これによって時間ベースの区間にレコードを集約することが可能です。この記事では、&lt;code&gt;bin()&lt;/code&gt;関数が特に有用なシナリオについて探ります。&lt;/p&gt;&#10;&lt;h2 id="binとは"&gt;&lt;code&gt;bin()&lt;/code&gt;とは？&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bin()&lt;/code&gt;関数は、レコードを時間間隔に基づいてグループ化します。これにより、ログデータを分、時間、日といった期間で分析することができます。構文は非常に簡単です：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bin(時間間隔)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この&lt;code&gt;時間間隔&lt;/code&gt;は、秒（&lt;code&gt;s&lt;/code&gt;）、分（&lt;code&gt;m&lt;/code&gt;）、時間（&lt;code&gt;h&lt;/code&gt;）などの複数の単位で表現できます。&lt;/p&gt;&#10;&lt;h2 id="特定のイベントの時間別カウント"&gt;特定のイベントの時間別カウント&#10;&lt;/h2&gt;&lt;p&gt;特定のイベントが時間にわたって何回発生したかをカウントしたい場合、&lt;code&gt;bin()&lt;/code&gt;を&lt;code&gt;stats count(*)&lt;/code&gt;と組み合わせて使用することができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34; and eventType = &amp;#34;何らかのイベント&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats count(*) by bin(10m)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| sort @timestamp desc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ユーザー活動の分析"&gt;ユーザー活動の分析&#10;&lt;/h2&gt;&lt;p&gt;時間区間でユーザー活動を分析したい場合、&lt;code&gt;bin()&lt;/code&gt;は効率的にデータをグループ化するのに役立ちます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message, message.payload.user_id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34; and message.payload.user_id = &amp;#34;特定のユーザーID&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats count(*) as userCount by bin(10m)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| sort @timestamp desc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="時間区間による比較"&gt;時間区間による比較&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bin()&lt;/code&gt;を使用することで、異なる時間区間でのメトリクスを簡単に比較することができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message, latency&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats avg(latency) by bin(1h)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="複数のbinの組み合わせ"&gt;複数の&lt;code&gt;bin()&lt;/code&gt;の組み合わせ&#10;&lt;/h2&gt;&lt;p&gt;単一のクエリ内で複数の&lt;code&gt;bin()&lt;/code&gt;を使用することで、複雑な時間ベースの集約を作成することが可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message, message.payload.user_id, eventType&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats count(*) by bin(10m), eventType&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bin()&lt;/code&gt;関数は、AWS CloudWatch Logs Insightsで時間ベースのログデータを集約・分析する際の強力なツールです。この関数を効果的に使用する方法を理解することで、アプリケーションの動作やパフォーマンスについてより深い洞察を得ることができます。特定のイベントをカウントしたい、ユーザー活動を分析したい、あるいはその他の時間ベースのログ分析を行いたい場合にも、&lt;code&gt;bin()&lt;/code&gt;はそれを簡単に実現する方法を提供しています。&lt;/p&gt;&#10;</description></item><item><title>文字列混じりのファイル名の数字部分をゼロ埋めするスクリプト</title><link>https://ai.hack-le.com/file-zero-padding/</link><pubDate>Sun, 24 Sep 2023 15:02:56 +0900</pubDate><guid>https://ai.hack-le.com/file-zero-padding/</guid><description>&lt;h2 id="背景"&gt;背景&#10;&lt;/h2&gt;&lt;p&gt;Linux や macOS などのシステムでよく使われる &lt;code&gt;ls&lt;/code&gt; コマンドで出力されたファイル名リストが整列されていないと、作業効率が下がることがあります。特に、ファイル名の後ろに数字がついている場合、&lt;code&gt;a1.png&lt;/code&gt;, &lt;code&gt;a2.png&lt;/code&gt;, &lt;code&gt;a10.png&lt;/code&gt; のように整列されていないことがよくあります。&lt;/p&gt;&#10;&lt;p&gt;この問題を解決するために、Fish シェルと Bash シェルで数字部分をゼロ埋めするスクリプトを作成します。&lt;/p&gt;&#10;&lt;h2 id="fish-シェル"&gt;Fish シェル&#10;&lt;/h2&gt;&lt;p&gt;Fish シェルでは以下のようにスクリプトを書きます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.png&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;set&lt;/span&gt; name &lt;span class="o"&gt;(&lt;/span&gt;string match -r &lt;span class="s2"&gt;&amp;#34;[a-zA-Z]+&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;set&lt;/span&gt; num &lt;span class="o"&gt;(&lt;/span&gt;string match -r &lt;span class="s2"&gt;&amp;#34;\d+&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;set&lt;/span&gt; new_num &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%02d&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$name$new_num&lt;/span&gt;&lt;span class="s2"&gt;.png&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ワンライナー"&gt;ワンライナー&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.png&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; name &lt;span class="o"&gt;(&lt;/span&gt;string match -r &lt;span class="s2"&gt;&amp;#34;[a-zA-Z]+&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; num &lt;span class="o"&gt;(&lt;/span&gt;string match -r &lt;span class="s2"&gt;&amp;#34;\d+&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; new_num &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%02d&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; mv &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$name$new_num&lt;/span&gt;&lt;span class="s2"&gt;.png&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="bash-シェル"&gt;Bash シェル&#10;&lt;/h2&gt;&lt;p&gt;Bash シェルでは以下のようにスクリプトを書きます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.png&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s2"&gt;&amp;#34;^[a-zA-Z]*&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s2"&gt;&amp;#34;[0-9]*&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;new_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%02d&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$name$new_num&lt;/span&gt;&lt;span class="s2"&gt;.png&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ワンライナー-1"&gt;ワンライナー&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.png&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s2"&gt;&amp;#34;^[a-zA-Z]*&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s2"&gt;&amp;#34;[0-9]*&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;new_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%02d&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$name$new_num&lt;/span&gt;&lt;span class="s2"&gt;.png&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事で紹介したスクリプトを使えば、&lt;code&gt;ls&lt;/code&gt; コマンドで出力されるファイル名の数字部分をゼロ埋めして、整列されたリストを得ることができます。Fish シェルと Bash シェルの両方で実現可能です。&lt;/p&gt;&#10;</description></item><item><title>カレントディレクトリのサブディレクトリを.cbz形式で圧縮するBashワンライナー</title><link>https://ai.hack-le.com/current-cbz/</link><pubDate>Sat, 23 Sep 2023 00:46:20 +0900</pubDate><guid>https://ai.hack-le.com/current-cbz/</guid><description>&lt;p&gt;自炊ユーザ必携スクリプト。カレントディレクトリにあるjpgの塊のサブフォルダを.cbzにするワンライナをChatGPTに書かせたのであった。昔コツコツ書いていた自作のスニペットもう全部不要……。&lt;/p&gt;&#10;&lt;h3 id="イントロ"&gt;イントロ&#10;&lt;/h3&gt;&lt;p&gt;BashおよびFishシェルは、UNIX系オペレーティングシステムにおいて、コマンドラインから操作するためのインターフェースを提供します。これらのシェルを利用することで、システムの様々なタスクを一行のコマンドで実行できます。本記事では、これらのシェルを使用して、サブディレクトリを&lt;code&gt;.cbz&lt;/code&gt;形式で圧縮する方法を紹介します。&lt;/p&gt;&#10;&lt;h3 id="bashでの実行"&gt;Bashでの実行&#10;&lt;/h3&gt;&lt;p&gt;Bashでは、以下のワンライナーを使用することで、カレントディレクトリに存在する全てのサブディレクトリを&lt;code&gt;.cbz&lt;/code&gt;形式で圧縮できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for dir in */; do dir_name=&amp;#34;${dir%/}&amp;#34;; zip -r &amp;#34;$dir_name.zip&amp;#34; &amp;#34;$dir_name&amp;#34;; mv &amp;#34;$dir_name.zip&amp;#34; &amp;#34;$dir_name.cbz&amp;#34;; done&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="fishでの実行"&gt;Fishでの実行&#10;&lt;/h3&gt;&lt;p&gt;Fishシェルでは、少し構文が異なります。以下のワンライナーを使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for dir in */; set dir_name (string trim -r -c &amp;#39;/&amp;#39; $dir); zip -r $dir_name.zip $dir_name; mv $dir_name.zip $dir_name.cbz; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="プロセスの説明"&gt;プロセスの説明&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;カレントディレクトリの全サブディレクトリをリストアップします。&lt;/li&gt;&#10;&lt;li&gt;各サブディレクトリに対して、ディレクトリ名から末尾のスラッシュ(&lt;code&gt;/&lt;/code&gt;)を削除し、その名前を変数にセットします。&lt;/li&gt;&#10;&lt;li&gt;次に、そのディレクトリをzip形式で圧縮します。&lt;/li&gt;&#10;&lt;li&gt;最後に、生成されたzipファイルの拡張子を&lt;code&gt;.zip&lt;/code&gt;から&lt;code&gt;.cbz&lt;/code&gt;に変更します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;.cbz形式は通常、コミックブックのリーダーアプリで使用される形式で、基本的にはzipアーカイブです。このワンライナーは、特にコミックや画像集の整理に有用で、シンプルでありながら、大量のディレクトリを効率的に圧縮するのに役立ちます。&lt;/p&gt;&#10;</description></item><item><title>シェルスクリプトで括弧を取り除く: BashとFishシェルのワンライナー</title><link>https://ai.hack-le.com/shell-remove-brackets/</link><pubDate>Sat, 23 Sep 2023 00:26:41 +0900</pubDate><guid>https://ai.hack-le.com/shell-remove-brackets/</guid><description>&lt;p&gt;例によってFishスクリプトの備忘録。これのあとにゼロ埋めすること多し。&lt;/p&gt;&#10;&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/shell-zero-padding/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;シェルスクリプトでファイル名をゼロ埋めする方法: BashとFishシェル&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/shell-zero-padding/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2023/09/6f9b1fd1af0f8fc4c9c4770d681c8deb.webp" alt="シェルスクリプトでファイル名をゼロ埋めする方法: BashとFishシェル" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;h3 id="はじめに"&gt;はじめに:&#10;&lt;/h3&gt;&lt;p&gt;カレントディレクトリに存在する &lt;code&gt;(数字).jpg&lt;/code&gt; 形式のファイル名から括弧 &lt;code&gt;()&lt;/code&gt; を取り除く方法について、BashシェルとFishシェルでの簡単なワンライナーを紹介します。&lt;/p&gt;&#10;&lt;h3 id="bash-シェル"&gt;Bash シェル:&#10;&lt;/h3&gt;&lt;p&gt;Bash シェルでは、次のワンライナーで、カレントディレクトリにある全ての &lt;code&gt;(*).jpg&lt;/code&gt; ファイル名から括弧を取り除くことができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="s1"&gt;&amp;#39;(&amp;#39;&lt;/span&gt;*&lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;*.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;*.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、例えば &lt;code&gt;(123).jpg&lt;/code&gt; というファイル名が &lt;code&gt;123.jpg&lt;/code&gt; に変更されます。&lt;/p&gt;&#10;&lt;h3 id="fish-シェル"&gt;Fish シェル:&#10;&lt;/h3&gt;&lt;p&gt;Fish シェルでは、以下のワンライナーで同様の操作が可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *&lt;span class="s1"&gt;&amp;#39;(&amp;#39;&lt;/span&gt;*&lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;*.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; new_file &lt;span class="o"&gt;(&lt;/span&gt;string replace -ra &lt;span class="s1"&gt;&amp;#39;[()]&amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; mv &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="nv"&gt;$new_file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この Fish シェルのワンライナーは、カレントディレクトリに存在する &lt;code&gt;(数字).jpg&lt;/code&gt; 形式のファイル名から、左括弧 &lt;code&gt;(&lt;/code&gt; と右括弧 &lt;code&gt;)&lt;/code&gt; を両方正しく取り除きます。&lt;/p&gt;&#10;&lt;h3 id="まとめ"&gt;まとめ:&#10;&lt;/h3&gt;&lt;p&gt;ファイル名から特定の文字を取り除くことは、ファイルの整理や管理を助けます。Bash シェルと Fish シェルのどちらでも、簡単なワンライナーでこの操作を行うことができます。&lt;/p&gt;&#10;</description></item><item><title>シェルスクリプトでファイル名をゼロ埋めする方法: BashとFishシェル</title><link>https://ai.hack-le.com/shell-zero-padding/</link><pubDate>Sat, 23 Sep 2023 00:22:50 +0900</pubDate><guid>https://ai.hack-le.com/shell-zero-padding/</guid><description>&lt;p&gt;画像のファイル整理中とかに時々出てくるシチュエーションのbash, fishのワンライナスニペット。毎回ChatGPTに聞くのも煩わしいので備忘録メモ。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに:&#10;&lt;/h2&gt;&lt;p&gt;数値で構成されたファイル名（例： &lt;code&gt;1.jpg&lt;/code&gt; 、 &lt;code&gt;10.jpg&lt;/code&gt; ）を3桁のゼロ埋め形式（例： &lt;code&gt;001.jpg&lt;/code&gt; 、 &lt;code&gt;010.jpg&lt;/code&gt; ）に変更する方法について解説します。ここでは、BashシェルとFishシェルの両方で利用可能なワンライナーコマンドを紹介します。&lt;/p&gt;&#10;&lt;h2 id="bash-シェル"&gt;Bash シェル:&#10;&lt;/h2&gt;&lt;p&gt;Bash シェルでは、次のワンライナーコマンドで、カレントディレクトリにある全ての &lt;code&gt;.jpg&lt;/code&gt; ファイル名をゼロ埋めできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^&lt;span class="o"&gt;([&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;jpg$ &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%03d.jpg&amp;#34;&lt;/span&gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_REMATCH&lt;/span&gt;&lt;span class="p"&gt;[1]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、カレントディレクトリに存在する全ての &lt;code&gt;.jpg&lt;/code&gt; ファイルを対象にし、数字だけのファイル名を3桁のゼロ埋めに変更します。&lt;/p&gt;&#10;&lt;h2 id="fish-シェル"&gt;Fish シェル:&#10;&lt;/h2&gt;&lt;p&gt;Fish シェルでは、次のワンライナーで同等の操作が可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -qE &lt;span class="s1"&gt;&amp;#39;^[0-9]+\.jpg$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; -l num &lt;span class="o"&gt;(&lt;/span&gt;string match -r &lt;span class="s1"&gt;&amp;#39;([0-9]+)&amp;#39;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)[&lt;/span&gt;2&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; mv &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;%03d.jpg&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; end&lt;span class="p"&gt;;&lt;/span&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fish シェルでこのコマンドを実行すると、カレントディレクトリにある数字だけの &lt;code&gt;.jpg&lt;/code&gt; ファイルが、3桁のゼロ埋め形式に変更されます。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ:&#10;&lt;/h2&gt;&lt;p&gt;シェルスクリプトを用いて、数値で構成されたファイル名をゼロ埋め形式に変更することは、ファイルの整理や管理を助けます。Bash シェルと Fish シェルのどちらも、簡単に同等の操作を実行することができます。&lt;/p&gt;&#10;</description></item><item><title>fishシェルの環境変数設定：-Ux vs -gx</title><link>https://ai.hack-le.com/fish-ux-vs-gx/</link><pubDate>Sun, 17 Sep 2023 12:50:48 +0900</pubDate><guid>https://ai.hack-le.com/fish-ux-vs-gx/</guid><description>&lt;p&gt;環境変数の設定方法いつも忘れてしまうので、メモっておく。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;fish&lt;/code&gt;シェルは、その直感的な機能とユーザーフレンドリーな設定方法で多くの開発者から支持を受けています。この記事では、&lt;code&gt;fish&lt;/code&gt;シェルで環境変数を設定する2つの一般的な方法、&lt;code&gt;-Ux&lt;/code&gt;と&lt;code&gt;-gx&lt;/code&gt;の違いと、それぞれの利点と欠点について詳しく説明します。&lt;/p&gt;&#10;&lt;h2 id="2つの方法"&gt;2つの方法&#10;&lt;/h2&gt;&lt;p&gt;大別して、&lt;code&gt;-Ux&lt;/code&gt;を使う方法と&lt;code&gt;-gx&lt;/code&gt;を使う方法があります。&lt;/p&gt;&#10;&lt;h3 id="-uxユニバーサル変数としてエクスポート"&gt;&lt;code&gt;-Ux&lt;/code&gt;：ユニバーサル変数としてエクスポート&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;set -U&lt;/code&gt;：変数を永続的なユニバーサル変数として設定します。これは、すべてのfishインスタンスで共有され、セッション間で保存される変数です。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;set -x&lt;/code&gt;：変数をエクスポートします。これにより、その変数が子プロセスに利用可能になります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;例として、&lt;code&gt;MY_VARIABLE&lt;/code&gt;という名前の環境変数を永続的に設定し、それをエクスポートしたい場合、次のようにコマンドを使用します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set -Ux MY_VARIABLE &amp;#34;Some Value&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを実行すると、&lt;code&gt;MY_VARIABLE&lt;/code&gt;はすべてのfishインスタンスと子プロセスで利用可能となります。そして、システムを再起動してもこの設定は保持されます。&lt;/p&gt;&#10;&lt;p&gt;ユニバーサル変数を削除する場合は、&lt;code&gt;set -e&lt;/code&gt;オプションとともに変数の名前を指定します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set -e MY_VARIABLE&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドにより、指定されたユニバーサル変数が削除されます。&lt;/p&gt;&#10;&lt;h4 id="メリット"&gt;メリット:&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;永続性&lt;/strong&gt;: すべてのセッション間で保持され、システム再起動後も失われません。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;共有&lt;/strong&gt;: すべての&lt;code&gt;fish&lt;/code&gt;インスタンス間で変数が共有されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;インタラクティブ設定&lt;/strong&gt;: コマンドラインから直接変数を設定・変更が可能です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="デメリット"&gt;デメリット:&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;オーバーヘッド&lt;/strong&gt;: 多くのユニバーサル変数を使用すると、起動時のオーバーヘッドが増加する可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;混乱の原因&lt;/strong&gt;: 変数の変更が他の全ての&lt;code&gt;fish&lt;/code&gt;インスタンスに影響します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="オススメするケース"&gt;オススメするケース:&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;共通の設定&lt;/strong&gt;: 複数の &lt;code&gt;fish&lt;/code&gt; セッションやインスタンス間で共有したい設定がある場合。例えば、特定のプログラムのパスを追加したいときなど。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;一時的な変更&lt;/strong&gt;: インタラクティブに変数を変更し、その設定を暫定的にすべてのセッションで利用したい場合。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;マシン全体の設定&lt;/strong&gt;: 複数のユーザーアカウント間で共有したい設定がある場合。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="-gxグローバル変数としてエクスポート"&gt;&lt;code&gt;-gx&lt;/code&gt;：グローバル変数としてエクスポート&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; オプションを使用して設定された変数は、グローバル変数として保存されます。&lt;/li&gt;&#10;&lt;li&gt;これは現在のセッション内でのみ存在し、新しいセッションやターミナルウィンドウで利用することはできません。&lt;/li&gt;&#10;&lt;li&gt;セッションが終了すると、グローバル変数も消失します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;いくつかの代表的な設定パターンを列挙します。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;PATH変数にディレクトリを追加する&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set -gx PATH $PATH /path/to/your/directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;新しい環境変数を設定する&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set -gx MY_VARIABLE &amp;#34;Some Value&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;既存の環境変数の値を変更する&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set -gx PATH &amp;#34;/new/path:$PATH&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらの設定を、設定ファイルに記述することで、セッションを開始する時に読み込まれます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano ~/.config/fish/config.fish&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="メリット-1"&gt;メリット:&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;明確な初期化&lt;/strong&gt;: 変数の初期化が明確になり、文書化しやすくなります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セッション固有&lt;/strong&gt;: 特定のセッションにのみ変数や設定を適用可能です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="デメリット-1"&gt;デメリット:&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;非永続性&lt;/strong&gt;: セッションが終了すると変数は消失します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;変更の手間&lt;/strong&gt;: 変数の変更のためには設定ファイルを編集し、新しいセッションを開始または設定ファイルを再読み込みする必要があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="オススメするケース-1"&gt;オススメするケース:&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;セッション固有の設定&lt;/strong&gt;: あるセッションに特定の変数や設定を適用したいが、他のセッションには影響を与えたくない場合。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;明確な管理&lt;/strong&gt;: セッションの設定や起動時の動作を明確に制御したい場合。&lt;code&gt;config.fish&lt;/code&gt; に明確な指示を書くことで、どの変数がセットされているか、なぜそれがそうなっているかを文書化しやすくなります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;多数の変数を設定&lt;/strong&gt;: 多くの環境変数を設定する場合、それらを一か所（&lt;code&gt;config.fish&lt;/code&gt;）にまとめることで、管理や変更が容易になります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-gxを推奨"&gt;&lt;code&gt;-gx&lt;/code&gt;を推奨&#10;&lt;/h2&gt;&lt;p&gt;一般的なシナリオでは、&lt;code&gt;-gx&lt;/code&gt;オプションを&lt;code&gt;config.fish&lt;/code&gt;に記述する方法が推奨されます。これにより、設定の一元管理が容易になり、意図しない変数の共有や競合を避けることができます。しかしながら、特定の状況やニーズに応じて&lt;code&gt;-Ux&lt;/code&gt;オプションを選択することも有効です。&lt;/p&gt;&#10;&lt;p&gt;環境変数の設定方法は、その用途やニーズに応じて最も適した方法を選択することが重要です。どちらの方法を選ぶかは、具体的な使用ケースやニーズに応じて異なるため、各プロジェクトやタスクの要件をよく理解し、適切な選択をするよう努めましょう。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;こういう話題は得意だよねChatGPT。基本的には設定ファイルに書いてるかな。持ち運べるし。&lt;/p&gt;&#10;</description></item><item><title>Amazon Cognito: ID Tokenの取得するPythonコード</title><link>https://ai.hack-le.com/amazon-cognito-id-token-python/</link><pubDate>Sun, 17 Sep 2023 12:36:02 +0900</pubDate><guid>https://ai.hack-le.com/amazon-cognito-id-token-python/</guid><description>&lt;p&gt;テストの時とかで、CognitoのID Tokenをさらっとほしいことがある。なので、ChatGPT-4にお願いした備忘録。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;Amazon Cognitoは、ユーザー認証やアイデンティティの提供に関する多くの便利な機能を提供しています。この記事では、管理者権限を使用して特定のユーザのID Tokenを取得する方法について説明します。&lt;/p&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;AWSのアカウント&lt;/li&gt;&#10;&lt;li&gt;Python環境&lt;/li&gt;&#10;&lt;li&gt;Boto3ライブラリのインストール&lt;/li&gt;&#10;&lt;li&gt;Cognito User PoolとApp Clientの作成済み&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ステップバイステップガイド"&gt;ステップバイステップガイド&#10;&lt;/h2&gt;&lt;h3 id="1-boto3のインストール"&gt;1. Boto3のインストール&#10;&lt;/h3&gt;&lt;p&gt;Boto3はAWSの公式SDKです。以下のコマンドでインストールできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pythonコードの準備"&gt;Pythonコードの準備&#10;&lt;/h3&gt;&lt;p&gt;以下は、指定されたユーザプールとクライアントアプリで指定されたユーザのID Tokenを取得するPythonコードです。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_id_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_pool_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cognito-idp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin_initiate_auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UserPoolId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_pool_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ClientId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AuthFlow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ADMIN_NO_SRP_AUTH&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AuthParameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;USERNAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;PASSWORD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ID Tokenを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;id_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AuthenticationResult&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;IdToken&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;id_token&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# パラメータ設定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USER_POOL_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-user-pool-id&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-client-id&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USERNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;target-username&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;target-user-password&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# 管理者として取得する場合、正確なパスワードを知っている必要があります&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_id_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USER_POOL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="注意点"&gt;注意点&#10;&lt;/h3&gt;&lt;p&gt;このアプローチにはいくつか注意点があります:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;管理者の権限を必要とします。&lt;/li&gt;&#10;&lt;li&gt;ユーザーのパスワードを直接知っている必要があります。&lt;/li&gt;&#10;&lt;li&gt;セキュリティ対策やIAMポリシーの適切な設定も考慮する必要があります。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;Amazon Cognitoを使用してID Tokenを取得する方法は複数ありますが、管理者として特定のユーザーのID Tokenを取得する際のアプローチについて解説しました。セキュリティの観点から注意深く使用することを忘れないでください。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;珍しく何事もなくうまくいった。&lt;/p&gt;&#10;</description></item><item><title>AWS Lambda Powertoolsのタイムスタンプを読みやすいローカル時刻に変換するJavaScriptのスニペット</title><link>https://ai.hack-le.com/aws-lambda-powertools-timestamp/</link><pubDate>Wed, 09 Aug 2023 13:22:37 +0900</pubDate><guid>https://ai.hack-le.com/aws-lambda-powertools-timestamp/</guid><description>&lt;p&gt;AWS Lambda PowertoolsはLambda関数使い必携の便利ユーティリティなわけだが、なぜかこれのloggerで自動的に記録されるタイムスタンプの形式が、&lt;code&gt;2021-05-03 10:20:19, 650+0200&lt;/code&gt;のようなよくわからん形になっている。カンマ……？（参考記事: &lt;a class="link" href="https://aws.amazon.com/jp/builders-flash/202205/lambda-powertools-python-3/?awsf.filter-name=*all" target="_blank" rel="noopener"&#10; &gt;AWS Lambda Powertools Python入門 第 3 回 ~Logger Utility - 変化を求めるデベロッパーを応援するウェブマガジン | AWS&lt;/a&gt;）&lt;/p&gt;&#10;&lt;p&gt;まぁちょっと直せばDate型にできそうだなと思ったので、ChatGPT-4にスニペット書いてもらってついでに記事にした。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;AWS Lambda Powertoolsは非常に便利なユーティリティで、AWS Lambdaの開発を容易にするための数々の機能を提供しています。しかし、時にはそのロギングに使用される日付フォーマットが少しわかりづらくなることがあります。&lt;/p&gt;&#10;&lt;p&gt;例: &lt;code&gt;2023-08-09 03:58:10,866+0000&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;この記事では、この特定のタイムスタンプの形式をJavaScriptでローカル時刻に変換する方法について説明します。&lt;/p&gt;&#10;&lt;h2 id="タイムスタンプの解析"&gt;タイムスタンプの解析&#10;&lt;/h2&gt;&lt;p&gt;このタイムスタンプの形式は標準的なものではないため、少し工夫して変換する必要があります。以下はその手順です。&lt;/p&gt;&#10;&lt;h3 id="手順"&gt;手順&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;カンマをドットに置換する&lt;/strong&gt;:タイムスタンプにはカンマが使用されているため、最初にドットに置換します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Dateオブジェクトの作成&lt;/strong&gt;:カンマをドットに置換した後、JavaScriptのDateオブジェクトを作成します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ローカル時刻に変換する&lt;/strong&gt;:Dateオブジェクトをローカル時刻に変換します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="コード例"&gt;コード例&#10;&lt;/h3&gt;&lt;p&gt;以下は、このタイムスタンプをローカル時刻に変換するコード例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2023-08-09 03:58:10,866+0200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adjustedTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adjustedTimestamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、与えられた日付と時刻をJavaScriptのDateオブジェクトに変換し、その後&lt;code&gt;toLocaleString&lt;/code&gt;メソッドを使用してローカル時刻に変換します。&lt;/p&gt;&#10;&lt;p&gt;ただし、この例のタイムスタンプの形式が標準的でないため、一部のブラウザではうまく動作しない可能性があります。もし問題がある場合は、以下のようにタイムスタンプを手動で解析することもできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2021-05-03 10:20:19,650+0200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[- :+,]/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// オフセットの部分を取得して、分単位に変換&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Date.UTCでUTC時刻を計算し、オフセットを考慮&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、与えられた文字列を解析して日付、時刻、およびタイムゾーンの各部分を取得し、それらを使用してDateオブジェクトを構築します。そして、このDateオブジェクトをローカル時刻に変換します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;標準的な日付フォーマットとは異なるものに対処する際には、このように少し手間がかかることがあります。もし、このような変換がプロジェクトで頻繁に必要な場合、共通のユーティリティ関数として切り出して再利用すると良いかもしれません。&lt;/p&gt;&#10;&lt;p&gt;また、日付操作のライブラリ（例：moment.js、date-fnsなど）を使用することも考慮に入れると良いかもしれません。これらのライブラリは、様々なフォーマットの日付を扱う際に非常に便利です。&lt;/p&gt;&#10;&lt;p&gt;このユーティリティを使用して開発する際に役立つことを願っています。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;こんなスニペットでも記事にしておくと案外役に立つものなので、備忘録。オフセットがある場合とか地味にしんどいわ（普通UTCかローカルタイムのどっちかだと思うけど）。ただ簡単な記事だが、オフセットの計算で一度ChatGPTが謎の暴走していたりする……。絵文字使って言い訳しててなんか笑った。&lt;/p&gt;&#10;</description></item><item><title>AWS LambdaとCloudWatch Logs Insightsを組み合わせて効率的にログ分析</title><link>https://ai.hack-le.com/aws-lambda-cloudwatch-logs-insights/</link><pubDate>Thu, 03 Aug 2023 17:10:03 +0900</pubDate><guid>https://ai.hack-le.com/aws-lambda-cloudwatch-logs-insights/</guid><description>&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/aws-cloudwatch-logs-insights/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;AWS CloudWatch Logs Insightsで効率的なログ分析&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/aws-cloudwatch-logs-insights/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2023/08/a236f3f9feb84cf10e6d4e3cd98251ac.png" alt="AWS CloudWatch Logs Insightsで効率的なログ分析" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;前回の記事の続き。ローカルで実行したCloudWatch Logs Insightsを使ったコードを、Lambda関数で実行するよ。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS LambdaとCloudWatch Logs Insightsを連携させることで、自動化された効率的なログ分析が可能になります。この記事では、その設定方法からテスト実行までの手順を詳しく説明します。&lt;/p&gt;&#10;&lt;p&gt;以下は、Lambda関数を使用してCloudWatch Logs Insightsからログを取得する一連の手順です。&lt;/p&gt;&#10;&lt;h2 id="iamロールの作成"&gt;IAMロールの作成&#10;&lt;/h2&gt;&lt;p&gt;Lambda関数に適切な権限を持たせるために、関数に割り当てるIAMロールにCloudWatch Logs Insightsへのアクセス権限を付与する必要があります。この権限は、&lt;code&gt;logs:StartQuery&lt;/code&gt;, &lt;code&gt;logs:GetQueryResults&lt;/code&gt;, &lt;code&gt;logs:StopQuery&lt;/code&gt; などが含まれます。&lt;/p&gt;&#10;&lt;p&gt;AWS Webコンソールを使用してLambda関数に適切なIAMロールを作成するには、以下の手順を実施します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Management Console&lt;/strong&gt;にログインし、&lt;strong&gt;IAM&lt;/strong&gt; サービスに移動します。&lt;/li&gt;&#10;&lt;li&gt;左側のメニューから&lt;strong&gt;ロール&lt;/strong&gt;を選択し、「&lt;strong&gt;ロールの作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;AWSサービス&lt;/strong&gt;を選択し、&lt;strong&gt;Lambda&lt;/strong&gt;をクリックして、「&lt;strong&gt;次のステップ: アクセス権限&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;ポリシーの作成&lt;/strong&gt;」 ボタンをクリックして新しいポリシーを作成します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;JSON&lt;/strong&gt;タブを選択し、以下のポリシーを入力します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Sid&amp;#34;: &amp;#34;VisualEditor0&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;logs:StartQuery&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;logs:GetQueryResults&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;logs:StopQuery&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;上記のポリシーは、CloudWatch Logs Insightsにクエリを投げるための基本的なアクションを許可しています。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;タグ&lt;/strong&gt;」 タブをクリックして必要なタグを追加し、「&lt;strong&gt;次のステップ: 確認&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;ポリシーの名前と説明を入力し、「&lt;strong&gt;ポリシーの作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;作成したポリシーを選択し、「&lt;strong&gt;次のステップ: タグ&lt;/strong&gt;」 ボタンをクリックして必要なタグを追加します。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;次のステップ: 確認&lt;/strong&gt;」 ボタンをクリックし、ロールの名前と説明を入力して、「&lt;strong&gt;ロールの作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;これで、Lambda関数からCloudWatch Logs Insightsのクエリを実行するためのIAMロールが作成されました。このロールをLambda関数の作成時に選択して使用します。&lt;/p&gt;&#10;&lt;p&gt;（著者注記: 文言微妙に変わってるかも。名前とかは適当に）&lt;/p&gt;&#10;&lt;h2 id="lambda関数の作成"&gt;Lambda関数の作成&#10;&lt;/h2&gt;&lt;p&gt;Pythonを使用してLambda関数を作成し、CloudWatch Logs Insightsへのクエリを実行するコードを記述します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Management Console&lt;/strong&gt;にログインし、&lt;strong&gt;Lambda&lt;/strong&gt; サービスに移動します。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;関数の作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;一から作成&lt;/strong&gt;」 を選択し、関数名とランタイム（Python 3.x）を選択します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;IAMロール&lt;/strong&gt; に先ほど作成したロールを適用します&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;関数の作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;関数コードエディタで下記のLambda関数のコードを貼り付けます。&lt;/li&gt;&#10;&lt;li&gt;Deployします&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;logs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-log-group-name&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start_query_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logGroupName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;log_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# 開始時間（UNIXタイムスタンプ、ミリ秒）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# 終了時間（UNIXタイムスタンプ、ミリ秒）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queryString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fields @timestamp, @message | filter level=&amp;#39;INFO&amp;#39; | sort @timestamp desc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_query_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;queryId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_query_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Complete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;results&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="テストの実行"&gt;テストの実行&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;「&lt;strong&gt;テスト&lt;/strong&gt;」 ドロップダウンメニューをクリックし、「&lt;strong&gt;新しいテストイベントの設定&lt;/strong&gt;」 を選びます。&lt;/li&gt;&#10;&lt;li&gt;テストイベントの名前を入力します。特に入力などはないので、hello-worldテンプレートをそのまま使って問題ありません&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;作成&lt;/strong&gt;」 ボタンをクリックしてテストイベントを作成します。&lt;/li&gt;&#10;&lt;li&gt;新しく作成したテストイベントが選択されていることを確認し、「&lt;strong&gt;テスト&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;実行が完了すると、結果ペインに関数の結果が表示されます。ここには、戻り値やログ出力、実行時間などの詳細が含まれます。&lt;/li&gt;&#10;&lt;li&gt;結果ペインの下部にある「ログを表示」 リンクをクリックすると、完全なログ出力をCloudWatch Logsで確認することができます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;この手順により、AWS WebコンソールからLambda関数をテスト実行し、結果とログを確認することができます。関数の挙動を調整したい場合は、コードを編集し、再度テストを実行して確認します。&lt;/p&gt;&#10;&lt;p&gt;初期設定の3秒ではタイムアウトが発生する場合、下記手順によりタイムアウトを増加させます。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Lambda関数のページで「設定」 タブをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;一般設定&lt;/strong&gt;」 セクションで「編集」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;タイムアウト&lt;/strong&gt;」 の値を増やし（例: 30秒）、「&lt;strong&gt;保存&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS LambdaとCloudWatch Logs Insightsを組み合わせることで、自動化された効率的なログ分析が容易になります。この記事の手順に従い、独自の分析タスクを自動化してみてください。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;内容的にちょっと複雑なためか、記事は会話の内容を自分でかなりツギハギしている。さすがにこの内容を一発で出してくれるほど有能ではない模様。でも、イチから自分で書くよりよっぽど楽だね。&lt;/p&gt;&#10;</description></item><item><title>AWS CloudWatch Logs Insightsで効率的なログ分析</title><link>https://ai.hack-le.com/aws-cloudwatch-logs-insights/</link><pubDate>Thu, 03 Aug 2023 16:18:49 +0900</pubDate><guid>https://ai.hack-le.com/aws-cloudwatch-logs-insights/</guid><description>&lt;p&gt;AWS CloudWatch Log Insights便利だよね。まぁまぁコストはかかるけれど。これをプログラム的に実行するためのスニペットをChatGPT-4に書いてもらったので、その備忘録記事。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;ログ分析はシステムの監視とトラブルシューティングに不可欠です。AWSを使ったシステムにおいては、AWS CloudWatch Logs Insightsを使用すると、ログデータを対話的に検索し分析することができます。この記事では、特定の時間範囲と条件でログを効率的に抽出する方法をPythonのBoto3ライブラリを使用して説明します。&lt;/p&gt;&#10;&lt;h2 id="cloudwatch-logs-insightsの概要"&gt;CloudWatch Logs Insightsの概要&#10;&lt;/h2&gt;&lt;p&gt;AWS CloudWatch Logs Insightsは、Amazon CloudWatch Logs内のログデータを分析するための強力な対話型クエリエンジンです。大量のログデータから情報を素早く取得することが可能であり、運用監視やトラブルシューティングに役立ちます。&lt;/p&gt;&#10;&lt;p&gt;以下のような昨日を持っています。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;対話的なクエリ言語&lt;/strong&gt;: 特殊なクエリ言語を使用して、ログデータから必要な情報を素早く抽出できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;時間範囲のフィルタリング&lt;/strong&gt;: クエリの実行を特定の時間範囲に制限して、分析を高速化できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ビジュアル化&lt;/strong&gt;: クエリ結果をグラフやチャートで視覚的に表示できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;プログラムからのアクセス&lt;/strong&gt;: Boto3などのSDKを使用して、プログラムからクエリを実行できます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="クエリの作成と実行"&gt;クエリの作成と実行&#10;&lt;/h2&gt;&lt;p&gt;クエリは次のようなコンポーネントから構成されます：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;fields&lt;/code&gt;: 取得するフィールドを指定。例：&lt;code&gt;fields @timestamp, @message&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;filter&lt;/code&gt;: 条件に一致するログエントリをフィルタリング。例：&lt;code&gt;filter level='INFO'&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;sort&lt;/code&gt;: 特定のフィールドで結果を並べ替え。例：&lt;code&gt;sort @timestamp desc&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;limit&lt;/code&gt;: 結果の数を制限。例：&lt;code&gt;limit 20&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;例をあげましょう。以下のような構造的なjsonデータをCloudWatch Logsに出力しているとします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;level&amp;#34;: &amp;#34;INFO&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;message&amp;#34;: &amp;#34;...&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;level=&amp;ldquo;INFO&amp;quot;のものだけを抽出し、直近の時間のものから並べるのは、以下のようなクエリで可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message | filter level=&amp;#39;INFO&amp;#39; | sort @timestamp desc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="pythonとboto3でのクエリの実行"&gt;PythonとBoto3でのクエリの実行&#10;&lt;/h2&gt;&lt;p&gt;PythonとBoto3を使用してクエリをプログラムで実行することもできます。以下は、特定のロググループについて、直近1時間のINFOデータを抽出するプログラムの例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;logs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-log-group-name&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;start_query_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logGroupName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;log_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queryString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fields @timestamp, @message | filter level=&amp;#39;INFO&amp;#39; | sort @timestamp desc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;query_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_query_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;queryId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_query_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Complete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;results&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、指定されたロググループと時間範囲でクエリを実行し、レベルが&lt;code&gt;INFO&lt;/code&gt;のログエントリを取得します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;CloudWatch Logs Insightsは、大規模なログデータの分析と検索に非常に効率的なツールです。特定のフィールドのフィルタリング、並び替え、制限など、柔軟なクエリオプションが提供されています。プログラムからも簡単にアクセスできるため、自動化された分析やダッシュボードの作成にも適しています。これにより、システムの監視と分析がより効率的になります。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;コードはちょっと手直しが必要だったが、普通に動いてくれたのでまぁよかったね。最初はすべてのログストリームを取得してプログラムでフィルタするという全然違うやり方を提案されて、えぇー、そんな馬鹿なと思って突っ込んで聞いたら、ちゃんとCloudWatch Logs Insightsを使ったやり方を教えてくれた。ChatGPTは本当にそういうところがある。&lt;/p&gt;&#10;&lt;p&gt;質問リンクは以下。興味がある人はどうぞ。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://chat.openai.com/share/d3ae4555-46e3-4573-bc85-26ca34491ab5" target="_blank" rel="noopener"&#10; &gt;https://chat.openai.com/share/d3ae4555-46e3-4573-bc85-26ca34491ab5&lt;/a&gt;&lt;/p&gt;&#10;&lt;h2 id="lambdaバージョン"&gt;Lambdaバージョン&#10;&lt;/h2&gt;&lt;p&gt;続きの記事でLambda関数使ったやり方書きました。&lt;/p&gt;&#10;&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/aws-lambda-cloudwatch-logs-insights/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;AWS LambdaとCloudWatch Logs Insightsを組み合わせて効率的にログ分析&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/aws-lambda-cloudwatch-logs-insights/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2023/08/7d4184c02862dca5ba613025c88e6bbc.png" alt="AWS LambdaとCloudWatch Logs Insightsを組み合わせて効率的にログ分析" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;</description></item><item><title>AWS SAMのテンプレートファイルでParameter Storeの値を取得する記述</title><link>https://ai.hack-le.com/aws-sam-cloudformation-parameter-store/</link><pubDate>Tue, 01 Aug 2023 09:00:00 +0900</pubDate><guid>https://ai.hack-le.com/aws-sam-cloudformation-parameter-store/</guid><description>&lt;p&gt;前の記事で「質問したことを備忘録として記事にまとめて」と言ったところ、なんと「次回は〜〜をします！お楽しみに！」とまさかの備忘録の次回作を勝手に予告されてしまってめっちゃ笑った。せっかくChatGPTが意欲的になったので、次回作を書いてもらったのだが、「パラメータストアの値をCloudformationで取得する（コードで取得しなくてよい）」という知らなかった方法を紹介されてめっちゃためになってしまった……。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS SAM (Serverless Application Model)を使用すると、サーバーレスアプリケーションのデプロイメントと管理が大幅に簡素化されます。一方、AWS Systems Manager Parameter Storeは、設定データやシークレットをセキュアに保存し、アプリケーションから簡単にアクセスすることができるサービスです。今回は、これら2つのサービスを組み合わせて、AWS SAMテンプレート内で直接Parameter Storeの値を取得する方法について解説します。&lt;/p&gt;&#10;&lt;h2 id="直接parameter-storeの値を取得"&gt;直接Parameter Storeの値を取得&#10;&lt;/h2&gt;&lt;p&gt;Lambda関数のコード内でAWS SDKを使用してParameter Storeからパラメータを取得する代わりに、AWS SAMテンプレート内でCloudFormationのサブスティテューション機能を使用してParameter Storeの値を直接取得することができます。&lt;/p&gt;&#10;&lt;p&gt;これは、以下のようにAWS SAMテンプレートを記述することで可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MyFunction:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::Serverless::Function&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Handler: index.handler&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Runtime: nodejs14.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; CodeUri: s3://my-bucket/my-function.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Variables:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MY_VARIABLE: !Sub &amp;#34;{{resolve:ssm:/path/to/parameter:1}}&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで、&lt;code&gt;!Sub&lt;/code&gt;はCloudFormationのサブスティテューション（置換）機能を使用しています。&lt;code&gt;&amp;amp;#123;&amp;amp;#123;resolve:ssm:/path/to/parameter:1&amp;amp;#125;&amp;amp;#125;&lt;/code&gt;は、バージョン1の&lt;code&gt;/path/to/parameter&lt;/code&gt;という名前のParameter Storeのパラメータの値を取得しています。&lt;code&gt;/path/to/parameter&lt;/code&gt;は実際のパラメータの名前に置き換えてください。&lt;/p&gt;&#10;&lt;p&gt;（著者注記: パス部分はパラメータストアのパラメータ名をそのまま入れたら良い）&lt;/p&gt;&#10;&lt;p&gt;この記述により、Lambda関数内では、&lt;code&gt;process.env.MY_VARIABLE&lt;/code&gt;のように通常の環境変数を参照するだけで、Parameter Storeのパラメータの値を取得することができます。&lt;/p&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;p&gt;この方法でパラメータを取得する際、実行はCloudFormationサービスにより行われます。そのため、CloudFormation自身がParameter Storeへのアクセス権限を持っている必要があります。通常、CloudFormationのService RoleはAWS管理ポリシー &lt;code&gt;AWSCloudFormationFullAccess&lt;/code&gt; をアタッチして作成され、このポリシーにはParameter Storeへのアクセス権限が含まれています。したがって、通常はService Roleを特別に設定する必要はありませんが、カスタムポリシーを使用してService Roleを作成した場合など、適切な権限が設定されていることを確認してください。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS SAMテンプレートとCloudFormationのサブスティテューション機能を使用することで、コード内でAWS SDKを使用せずに直接Parameter Storeからパラメータを取得することが可能になります。これにより、コードの見通しが良くなり、Parameter Storeのパラメータ管理がさらに便利になります。&lt;/p&gt;&#10;&lt;p&gt;次回は、AWS SAMテンプレートでのLambda Layerの利用について解説します。お楽しみに！&lt;/p&gt;&#10;&lt;p&gt;（著者注: そんな予定はない）&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;なんで備忘録だといってるのに次回予告するねんｗｗｗとか言ってたら、フツーに知らない情報書かれて焦った。ちゃんと動きました。ためになりました。&lt;/p&gt;&#10;&lt;p&gt;元々は環境変数の使い方とかいう超初歩的な記事を書いていたんだけれど、その中でしれっとパラメータストアの値を直接取得していて、「え、そんなことできるの？」となってしまった。毎回Lambda関数の中でGetParametersしてたっていうね。。。ためになりました。。。&lt;/p&gt;&#10;</description></item><item><title>AWS SAMでParameter Storeからパラメータを取得するためのIAMロールの作成</title><link>https://ai.hack-le.com/aws-sam-parameter-store-iam/</link><pubDate>Mon, 31 Jul 2023 09:00:00 +0900</pubDate><guid>https://ai.hack-le.com/aws-sam-parameter-store-iam/</guid><description>&lt;p&gt;AWS SAMでどこを参照して良いのかいつも迷子になるテンプレートファイルの書き方。パラメータストアはいつも使うやつではないので、たまに使おうとすると「どう書くんだっけ……」と忘れている。&lt;/p&gt;&#10;&lt;p&gt;ChatGPT-4に聞いて確認しました。結果、そもそもコードで取得しなくて良いということがわかりましたが（後述）、本記事自体はあくまでコードでパラメータを取得するためのIAMロールを作成する方法になります。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS SAM (Serverless Application Model) を使用してサーバーレスアプリケーションを構築する際、しばしば環境変数や設定値などをAWS Systems Manager Parameter Storeから取得する必要があります。これを適切に行うためには、Lambda関数に対してParameter Storeへのアクセス権限を持つIAMロールを付与する必要があります。本記事では、そのIAMロールをAWS SAMテンプレートでどのように定義すればよいかを詳しく解説します。&lt;/p&gt;&#10;&lt;h2 id="iamロールの作成"&gt;IAMロールの作成&#10;&lt;/h2&gt;&lt;p&gt;以下のYAML形式のコードスニペットは、AWS SAMテンプレート内でIAMロールを定義する方法を示しています。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MyRole:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::IAM::Role&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AssumeRolePolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#39;2012-10-17&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Principal:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Service:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - lambda.amazonaws.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - sts:AssumeRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Policies:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - PolicyName: ParameterStoreAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; PolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#39;2012-10-17&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ssm:GetParameters&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ssm:GetParameter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Resource: arn:aws:ssm:region:account-id:parameter/MyParameter&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このテンプレートでは、&lt;code&gt;MyRole&lt;/code&gt;という名前のIAMロールが作成され、このロールはLambdaサービスがAssumeRoleを行えるようになっています。また、そのロールには&lt;code&gt;ParameterStoreAccess&lt;/code&gt;という名前のポリシーが付与されており、このポリシーは&lt;code&gt;MyParameter&lt;/code&gt;という名前のParameter Storeのパラメータへのアクセスを許可しています。&lt;/p&gt;&#10;&lt;p&gt;ここで、&lt;code&gt;region&lt;/code&gt;と&lt;code&gt;account-id&lt;/code&gt;はそれぞれAWSリージョンとあなたのAWSアカウントIDを表します。これらを適切な値に置き換えてください。&lt;/p&gt;&#10;&lt;p&gt;補足情報:&lt;/p&gt;&#10;&lt;p&gt;この例ではパラメータ取得のための権限 (&lt;code&gt;ssm:GetParameters&lt;/code&gt; と &lt;code&gt;ssm:GetParameter&lt;/code&gt;) をIAMロールに付与していますが、他の権限も必要な場合はそれぞれ追加してください。また、特定のパラメータだけでなく、すべてのパラメータにアクセスする権限を付与したい場合は、リソースのARNを&lt;code&gt;arn:aws:ssm:region:account-id:parameter/*&lt;/code&gt;としてください。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS SAMテンプレートでIAMロールを適切に定義し、Lambda関数にParameter Storeへのアクセス権限を付与することで、安全にParameter Storeからパラメータを取得することが可能になります。これにより、サーバーレスアプリケーションの設定値管理を柔軟に行うことができます。&lt;/p&gt;&#10;&lt;p&gt;次回は、AWS SAMテンプレートでの環境変数の管理方法について詳しく解説します。お楽しみに！&lt;/p&gt;&#10;&lt;p&gt;（著者注：そんな予定はない）&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;次回作が出てきて笑ってしまった。そんな予定があったのかｗ&lt;/p&gt;&#10;&lt;p&gt;内容については動作確認済みです。適切だと思います。Pythonコードは以下ですね。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssm = boto3.client(&amp;#34;ssm&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TOKEN = ssm.get_parameters(Names=[os.environ[&amp;#34;パラメータ&amp;#34;]], WithDecryption=True)[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Parameters&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;][0][&amp;#34;Value&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ldquo;パラメータ&amp;quot;の値を取得して&lt;code&gt;TOKEN&lt;/code&gt;に突っ込んでいます。&lt;/p&gt;&#10;&lt;p&gt;ただし、これは実は冗長で、テンプレートファイルから直接取得することができます。次回は環境変数の管理方法ではなく、テンプレートファイルから直接取得する方法です。&lt;/p&gt;&#10;&lt;p&gt;以下は質問。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;AWS SAMのテンプレートで、パラメータストアから特定のパラメータについて取得するための権限の書き方は？&lt;/li&gt;&#10;&lt;li&gt;うまくいきました。適切なロールだったようですね。備忘録にしたいので、ブログ記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;備忘録だっつってんのに次回作書きたがるChatGPTｗwwとか言ってたら知らないこと書かれてしまった……。&lt;/p&gt;&#10;</description></item><item><title>WordPressでのシンタックスハイライトの導入</title><link>https://ai.hack-le.com/wordpress-syntax-highlighter/</link><pubDate>Thu, 27 Jul 2023 09:00:00 +0900</pubDate><guid>https://ai.hack-le.com/wordpress-syntax-highlighter/</guid><description>&lt;p&gt;このサイトにはプログラムのコードが多いので、さっさと入れるべきだったのだが、面倒臭くてしていなかった。これまでシンタックスハイライトはjsのライブラリを導入していたが、今となってはそんなことは面倒臭いので、プラグインを入れようと思っていた。しかしシンタックスハイライトのプラグインはたくさんあるので、どれがよいかわからず、手を付けられていなかった。&lt;/p&gt;&#10;&lt;p&gt;ChatGPT-4に聞けばいいんだと今更ながら気づき、色々聞いて導入した。まぁとりあえず動いている。以下、記事にまとめさせた。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;今回は、WordPressにシンタックスハイライトを導入する方法について説明します。シンタックスハイライトは、コードの読みやすさを向上させるための強力なツールです。&lt;/p&gt;&#10;&lt;p&gt;WordPressでコードのシンタックスハイライトを実装するには、主に以下の2つの方法があります。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;プラグインを使用する&lt;/li&gt;&#10;&lt;li&gt;CodeMirrorなどのライブラリを自分で導入する&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="プラグインを使用する"&gt;プラグインを使用する&#10;&lt;/h3&gt;&lt;p&gt;これは最も簡単で、特別な技術的スキルが必要ない方法です。プラグインをインストールし有効化するだけで、シンタックスハイライトが利用できるようになります。&lt;/p&gt;&#10;&lt;p&gt;以下にいくつかの一般的なプラグインを挙げておきます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Prism.js: 非常に軽量で、多くのプログラミング言語をサポートしています。WordPress用のPrism.jsプラグインは、「WP PrismJS」などがあります。&lt;/li&gt;&#10;&lt;li&gt;SyntaxHighlighter Evolved: 古くからあるプラグインで、多くの言語に対応しています。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="codemirrorなどのライブラリを自分で導入する"&gt;CodeMirrorなどのライブラリを自分で導入する&#10;&lt;/h3&gt;&lt;p&gt;もしより細かい制御が必要であれば、自分でJavaScriptライブラリを導入するという選択肢もあります。この方法は、シンタックスハイライトを手動で実装することになりますが、コードの見た目や動作を完全にカスタマイズできる利点があります。&lt;/p&gt;&#10;&lt;p&gt;CodeMirrorやHighlight.jsなどのライブラリを導入することで、このタスクを達成できます。ただし、これらのライブラリを使ってシンタックスハイライトを手動で実装するには、JavaScriptとWordPressのテーマのカスタマイズに精通している必要があります。&lt;/p&gt;&#10;&lt;h2 id="syntaxhighlighter-evolvedの導入"&gt;SyntaxHighlighter Evolvedの導入&#10;&lt;/h2&gt;&lt;p&gt;Prism.jsやEnlighter - Customizable Syntax Highlighterといった有名なプラグインもありますが、今回は、シンプルさを最優先に考えるため、&lt;strong&gt;SyntaxHighlighter Evolved&lt;/strong&gt;を導入することにします。&lt;/p&gt;&#10;&lt;p&gt;このプラグインはWordPressのコミュニティで長い間利用されてきたものであり、その簡単さと信頼性が評価されています。特に設定を多く行う必要はなく、ショートコードを使用して簡単にブログ記事やページにコードブロックを挿入できます。&lt;/p&gt;&#10;&lt;p&gt;多くのプログラミング言語をサポートしており、その使いやすさと直感的な操作性は、シンプルさを追求するユーザーには特に魅力的です。そのため、特に高度なカスタマイズや特殊な機能を必要としないのであれば、SyntaxHighlighter Evolvedは非常に良い選択となります。&lt;/p&gt;&#10;&lt;h3 id="インストール"&gt;インストール&#10;&lt;/h3&gt;&lt;p&gt;まずはプラグインのインストールから始めましょう。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;WordPressの管理ダッシュボードにログインします。&lt;/li&gt;&#10;&lt;li&gt;左側のメニューバーから「プラグイン」を選択し、「新規追加」をクリックします。&lt;/li&gt;&#10;&lt;li&gt;検索バーに「SyntaxHighlighter Evolved」を入力し、該当するプラグインを見つけます。&lt;/li&gt;&#10;&lt;li&gt;「今すぐインストール」をクリックします。&lt;/li&gt;&#10;&lt;li&gt;インストールが完了したら、「有効化」をクリックします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="コードブロックの追加"&gt;コードブロックの追加&#10;&lt;/h3&gt;&lt;p&gt;次に、記事にコードブロックを追加してみましょう。以下にその例を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[sourcecode language=&amp;#34;css&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;your code here&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[/sourcecode]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで、&lt;code&gt;language=&amp;quot;css&amp;quot;&lt;/code&gt;の部分は、ハイライトを適用する言語に応じて変更します。たとえば、JavaScriptのコードをハイライトする場合は&lt;code&gt;language=&amp;quot;js&amp;quot;&lt;/code&gt;とします。&lt;/p&gt;&#10;&lt;p&gt;Gutenbergにおいては、ブロックも用意されています。&lt;/p&gt;&#10;&lt;h3 id="追加の設定必要に応じて"&gt;追加の設定（必要に応じて）&#10;&lt;/h3&gt;&lt;p&gt;SyntaxHighlighter Evolvedはデフォルトの状態でも非常に良く機能しますが、必要に応じてさまざまな設定を調整することもできます。設定はダッシュボードの左側のメニューバーから「設定」を選択し、「SyntaxHighlighter」をクリックすることで行えます。&lt;/p&gt;&#10;&lt;h3 id="既存の記事にシンタックスハイライトを適用する"&gt;既存の記事にシンタックスハイライトを適用する&#10;&lt;/h3&gt;&lt;p&gt;しかし、既存の記事にシンタックスハイライトを適用するには、各記事を手動で編集してショートコードを追加する必要があります。これは、特に記事数が多い場合、一見大変そうに見えます。&lt;/p&gt;&#10;&lt;p&gt;データベースの検索置換ツールを使用すれば、一部の作業を自動化できるかもしれません。しかし、この方法は非常に注意が必要です。誤った操作が行われるとサイトに重大な問題を引き起こす可能性があります。したがって、必ず事前にデータベースのバックアップを取るなど、安全な手順を踏むようにしてください。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;結局のところ、既存の記事をどのように処理するかはあなた次第です。あなたのサイトはあなた自身のものです。必要に応じて、時間を見つけて徐々に修正するか、あるいは、特定の記事だけ修正することも可能です。&lt;/p&gt;&#10;&lt;p&gt;それにより、少なくとも新しい記事については、きれいにシンタックスハイライトされたコードを含むことができます。これは、コードの読みやすさを向上させ、読者にとってより価値のあるコンテンツを提供するための一歩となります。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;プラグインの比較については色々と聞いたのだが、結局試したのはSynataxHighliter Evolvedだけなので、詳細につちえは省いた。まぁ十分ちゃんと動いているのでよしとする。&lt;/p&gt;&#10;&lt;p&gt;このサイトは比較的新しいサイトであるので、手動で全部置き換えることができたのだが、本館にあたる「&lt;a class="link" href="https://hack-le.com/" target="_blank" rel="noopener"&#10; &gt;或る阿呆の記 - 見栄を張らない、背伸びをしない。 私はただの阿呆です。 嘘です。 since 2012.10.17.&lt;/a&gt;」で手動による置き換えはさすがにつらい。これについては置換ツール（Better Search Replaceを勧められた）を使えという、まぁそうねという回答がきたのだが、調べたところなぜか&lt;code&gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;/code&gt;と&lt;code&gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;/code&gt;の数が合わないということが判明し、そのまま置き換えられねーというかなんで数あわねーんだぬおおぉぉみたいなことになり、挫けた。まぁどうせ昔の記事なんてほとんどアクセスもされないので、比較的アクセスの多い記事については気が向いた時に置き換えるくらいにしたいと思う。&lt;/p&gt;&#10;&lt;p&gt;以下は今回の質問。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;WordPressで、コードのシンタックスハイライトをいい感じで簡単に実装したい&lt;/li&gt;&#10;&lt;li&gt;特にこだわりはないので、簡単さのほうが大事だから、プラグインが良い。いくつかの有名なプラグインを比較してくれ。&lt;/li&gt;&#10;&lt;li&gt;柔軟性や機能の豊富さと簡単さはしばしばトレードオフの関係にある。見た感じこれらのプラグインも例に漏れないようだ。 僕は機能の豊富さや柔軟性よりもシンプルさを重視している。その観点では、君は何が良いと思う？&lt;/li&gt;&#10;&lt;li&gt;オーケー。SyntaxHighlighter Evolvedの使い方を教えてくれ。&lt;/li&gt;&#10;&lt;li&gt;なるほど便利だ。しかし、過去の記事にあるコードにこれを適用しなおすのはたいへんだ。なんとかならないか？&lt;/li&gt;&#10;&lt;li&gt;置換する手順を詳細かつ具体的に教えてくれ&lt;/li&gt;&#10;&lt;li&gt;ちょっと検索してみたら、なぜか&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;と&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;の数が合わなかったよ……。どうやら過去の記事はぐちゃぐちゃになっているようだ。 個人サイトだし、ちょっと調べる気力はないな……。&lt;/li&gt;&#10;&lt;li&gt;はぁ、まぁ、とりあえず新しい記事についてはSyntaxHighlighterを使っていくとしよう。 ここまでの話をブログの記事としてまとめてくれ。適切に見出しをつけてくれ。&lt;/li&gt;&#10;&lt;li&gt;他のプラグインも同様のことが言えるだろう。その中でSyntaxHighlighter Evolvedを選んだのは何故かについて書きたい。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;最後のほうの質問については、なんか適当なことを言い始めたので打ち切った。&lt;/p&gt;&#10;</description></item><item><title>fish,bashでのPNGとJPGファイルのWebPへの一括変換</title><link>https://ai.hack-le.com/fishbash-png-jpg-webp/</link><pubDate>Wed, 26 Jul 2023 14:28:43 +0900</pubDate><guid>https://ai.hack-le.com/fishbash-png-jpg-webp/</guid><description>&lt;p&gt;単純な内容だけれどよく使うかつよく忘れるので。これ、本当はBardに書かせようと思っていたんだよね。でも、Bardはfishスクリプトだと言っているのにBashのスクリプトしか書いてくれなかった。あと日本語も通じづらくて、かなり明確に指示してやる必要がある。結論として、ChatGPT-4にはまだ及ばないなぁ、と。アホになっているという噂のChatGPT-4だが、それでも今出ているAIチャットでは一番なんじゃないだろうか。&lt;/p&gt;&#10;&lt;p&gt;ということで、記事を書かせた。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;こんにちは、皆さん。&lt;/p&gt;&#10;&lt;p&gt;今日はLinuxシェルを使ってカレントディレクトリのPNGとJPGファイルを一括でWebP形式に変換する方法についてご紹介します。この作業は、fish shellとbashの両方で実行可能です。Macのターミナルや、Windows上のWSL2でももちろん実行可能です。&lt;/p&gt;&#10;&lt;p&gt;前提条件として、この記事で用いる&lt;code&gt;convert&lt;/code&gt;コマンドはImageMagickの一部なので、事前にシステムにインストールしておく必要があります。&lt;/p&gt;&#10;&lt;h2 id="fish-shellでの変換"&gt;Fish Shellでの変換&#10;&lt;/h2&gt;&lt;p&gt;まず、Fish Shellを使った方法から見ていきましょう。以下のワンライナーを実行すると、カレントディレクトリの全ての&lt;code&gt;.png&lt;/code&gt;と&lt;code&gt;.jpg&lt;/code&gt;ファイルが&lt;code&gt;.webp&lt;/code&gt;に変換されます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.png *.jpg&lt;span class="p"&gt;;&lt;/span&gt; convert &lt;span class="nv"&gt;$file&lt;/span&gt; -format webp &lt;span class="o"&gt;(&lt;/span&gt;basename -s &lt;span class="o"&gt;(&lt;/span&gt;string match -r &lt;span class="s2"&gt;&amp;#34;\..+&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.webp&lt;span class="p"&gt;;&lt;/span&gt; end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、まず&lt;code&gt;*.png *.jpg&lt;/code&gt;というパターンで全てのPNGとJPGファイルを選択します。そして、&lt;code&gt;convert&lt;/code&gt;コマンド（ImageMagickの一部として提供されている）を使ってそれぞれのファイルを&lt;code&gt;.webp&lt;/code&gt;フォーマットに変換します。&lt;/p&gt;&#10;&lt;h2 id="bashでの変換"&gt;Bashでの変換&#10;&lt;/h2&gt;&lt;p&gt;次に、Bashを使った方法を見ていきましょう。以下のワンライナーを実行すると、同様にカレントディレクトリの全ての&lt;code&gt;.png&lt;/code&gt;と&lt;code&gt;.jpg&lt;/code&gt;ファイルが&lt;code&gt;.webp&lt;/code&gt;に変換されます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; file in *.&lt;span class="o"&gt;{&lt;/span&gt;png,jpg&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; convert &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -format webp &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドでは、&lt;code&gt;*.{png,jpg}&lt;/code&gt;というパターンマッチングを使用して.pngと.jpgファイルを一度に全て選択します。そして、&lt;code&gt;&amp;quot;${file%.*}.webp&amp;quot;&lt;/code&gt;という表現を用いて元のファイル名から拡張子を取り除き、新しい&lt;code&gt;.webp&lt;/code&gt;拡張子を追加します。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;以上が、Fish ShellとBashを使ってPNGとJPGファイルをWebPに一括変換する方法です。このようなスクリプトは、特に大量の画像ファイルを効率的に変換したいときに非常に便利です。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;実家のような安心感。なんだかんだでChatGPT-4パイセンが今のところナンバーワンですわ……。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;fishでカレントディレクトリのすべてのpngをwebpにconvertするワンライナ&lt;/li&gt;&#10;&lt;li&gt;いいね。pngだけではなくjpgについてもやりたい時は？&lt;/li&gt;&#10;&lt;li&gt;ありがとう。 ここまでの内容を、ブログの記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;質問の数もシンプル。&lt;/p&gt;&#10;</description></item><item><title>Node.jsのバージョン一覧をCLIから取得する方法</title><link>https://ai.hack-le.com/node-js-cli/</link><pubDate>Wed, 19 Jul 2023 15:54:41 +0900</pubDate><guid>https://ai.hack-le.com/node-js-cli/</guid><description>&lt;p&gt;fishではnvmのサポートが微妙ということで、Node.jsのバージョン管理にはvoltaを使うことにした。が、voltaは配布されているNodeのバージョン一覧を取得するコマンドがない。まぁ &lt;code&gt;volta install node@18&lt;/code&gt;とかでざっくりインストールすればいいからだと思うが。まぁそうは言っても、バージョン一覧をCLIから取得したいなぁと思って、ChatGPT-4に聞いた。&lt;/p&gt;&#10;&lt;h2 id="環境"&gt;環境&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;M2 Pro MacBook Pro 14インチ&lt;/li&gt;&#10;&lt;li&gt;macOS 13.4.1&lt;/li&gt;&#10;&lt;li&gt;fish 3.6.1&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;Node.jsはJavaScriptをサーバーサイドで実行するための環境で、そのバージョン管理は重要な作業の一部です。今日は、Node.jsの公式配布元から利用可能なすべてのNode.jsのバージョンを一覧表示する方法を紹介します。これにより、特定のバージョンが存在するか確認したり、どのバージョンをインストールすべきか決定する際の参考にすることができます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="nodejsのバージョン一覧を取得するコマンド"&gt;Node.jsのバージョン一覧を取得するコマンド&#10;&lt;/h2&gt;&lt;p&gt;以下のコマンドを使用します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s https://nodejs.org/dist/ &lt;span class="p"&gt;|&lt;/span&gt; grep -Eo &lt;span class="s1"&gt;&amp;#39;v[0-9]+\.[0-9]+\.[0-9]+/&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/\///g&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sort -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下のような出力が得られます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v0.1.14&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v0.1.14&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v0.1.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v0.1.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.1.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.2.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.2.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.3.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.3.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.3.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.3.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.4.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v20.4.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは以下の操作を行っています：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;curl -s https://nodejs.org/dist/&lt;/code&gt;：Node.jsの公式配布元からHTMLを取得します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;grep -Eo 'v[0-9]+\.[0-9]+\.[0-9]+/'&lt;/code&gt;：取得したHTMLからバージョン番号を抽出します。&lt;code&gt;-E&lt;/code&gt;オプションは拡張正規表現を使用することを指定し、&lt;code&gt;-o&lt;/code&gt;オプションは一致した部分のみを出力します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;sed 's/\///g'&lt;/code&gt;：バージョン番号の末尾にあるスラッシュ(&lt;code&gt;/&lt;/code&gt;)を削除します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;sort -V&lt;/code&gt;：バージョン番号を順番に並べ替えます。&lt;code&gt;-V&lt;/code&gt;オプションはバージョン番号のような形式を正しくソートすることを指定します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;p&gt;このコマンドはUNIXベースのシステム（LinuxやmacOSなど）で動作します。Windowsの場合、同等の操作を行うためにはWindows Subsystem for Linux（WSL）や、cygwin、git bashなどのツールが必要です。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;Node.jsのバージョン管理は、プロジェクトの安定性や互換性を確保するために重要です。今回紹介したコマンドを使えば、CLIから簡単にNode.jsのバージョン一覧を取得でき、適切なバージョンの選択に役立つでしょう。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;質問一発で返ってきそうだが、以外にも引っかかっている。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;node.jsのマネージャであるvoltaでnodeを入れたいのだが、インストールできるバージョンの一覧はどのように取得できるのか&lt;/li&gt;&#10;&lt;li&gt;コマンドラインからNode.jsで配布されているバージョンを簡単に取得するにはどうしたらよいか&lt;/li&gt;&#10;&lt;li&gt;grep: invalid option &amp;ndash; P usage: grep [-abcdDEFGHhIiJLlMmnOopqRSsUVvwXxZz] [-A num] [-B num] [-C[num]] [-e pattern] [-f file] [&amp;ndash;binary-files=value] [&amp;ndash;color=when] [&amp;ndash;context[=num]] [&amp;ndash;directories=action] [&amp;ndash;label] [&amp;ndash;line-buffered] [&amp;ndash;null] [pattern] [file &amp;hellip;] とエラーが出た。Macのターミナルで実行した。&lt;/li&gt;&#10;&lt;li&gt;何も出力されない。awkによる抽出が失敗していると見られる。curlのレスポンスを一部抜粋した。これを見て修正できるか。（コードを貼る）&lt;/li&gt;&#10;&lt;li&gt;うまく動いた！ 備忘録としてブログにまとめたい。CLIからnodeのバージョン一覧を取得する方法について、ブログ記事としてまとめてくれ。適切に見出しを入れてくれ。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;失敗したが、実際の出力を貼ることでうまくいった。&lt;/p&gt;&#10;</description></item><item><title>なぜDropbox Plus の契約を2年以上残しながらAmazonプライムデーでNASを購入したのか</title><link>https://ai.hack-le.com/dropbox-plus-2-amazon/</link><pubDate>Tue, 18 Jul 2023 02:07:12 +0900</pubDate><guid>https://ai.hack-le.com/dropbox-plus-2-amazon/</guid><description>&lt;p&gt;「AmazonプライムデーでNASを買ったので、インタビュー記事にしてくれ」という意味不明な要望をChatGPT-4にした。こんなくだらないインタビューさせられるAI可哀想。だいじょうぶ、AIだから。&lt;/p&gt;&#10;&lt;p&gt;ちなみにNASは今うちのキッチンで動いているよ。一応QsyncとかDropboxっぽいことできるみたいだけど、基本的にはあまり動かさないデータのバックアップとメディアサーバ用途で動かすかなぁ。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;オンラインストレージの巨人Dropboxに縛られることなく、自分だけのクラウドを持つ。その夢を見ているユーザーがいます。彼は、未だ2年半の契約期間が残るDropboxを離れ、先日のAmazonプライムデーでNASを購入しました。では、その動機とは何なのでしょうか？&lt;/p&gt;&#10;&lt;h2 id="モチベーション"&gt;モチベーション&#10;&lt;/h2&gt;&lt;p&gt;彼の選択の背後には、いくつもの要素が絡み合っています。まず第一に、Appleのクラウドストレージポリシーの変更が挙げられます。彼は長年Mac miniを使用してきましたが、その最近のモデルはストレージの拡張性が制限されています。そのため、これまでは外付けSSDにデータを保存し、それをDropboxで同期していたのですが、Appleの方針が変わり、外部ストレージでのクラウドストレージの利用が制限される可能性が出てきました。&lt;/p&gt;&#10;&lt;p&gt;次に、彼のデータ量が増加している点です。特に彼が生成AIで扱うデータが増えたことから、今後より大容量のメディアを扱う必要が出てきそうだと感じていました。&lt;/p&gt;&#10;&lt;p&gt;そして最後に、AmazonプライムデーでのNASの価格引きが大きな要素となりました。もともとNASに対する興味はあったものの、それほど必要性を感じていなかった彼にとって、この機会が決断を後押ししました。円安による物価上昇が続く中で、プライムデーの割引は大いに魅力的だったのです。&lt;/p&gt;&#10;&lt;p&gt;これらの要素が重なり合った結果、彼はNASへの移行を決断しました。それは、自分だけのプライベートクラウドを作るという新たなステップへの一歩でした。&lt;/p&gt;&#10;&lt;h2 id="それぞれの長所短所"&gt;それぞれの長所・短所&#10;&lt;/h2&gt;&lt;p&gt;彼が語るDropboxの長所として最も際立つのは、その便利さです。Dropboxは手軽に複数のデバイス間でデータの同期を行うことができるサービスで、これほど簡単にデータを管理・共有できるツールは他にはありません。また、災害時のデータ保護も重要な要素です。万が一、地元で自然災害が発生したとしても、クラウド上に保存されているデータはその影響を受けません。&lt;/p&gt;&#10;&lt;p&gt;しかし、一方で彼はDropboxのいくつかの欠点についても語りました。その一つがランニングコストの高さです。クラウドストレージは便利ではありますが、その利便性を享受するためには定期的な費用が必要で、それが彼にとっては重荷となりました。さらに、Dropboxの提供する2TBという容量は、彼のように大量のデータを扱うユーザーにとっては限界が見えてきます。また、他のクラウドストレージサービスの問題例として、自分の子供との入浴写真が児童ポルノと誤認されてアカウントを凍結された報告など、プライバシーに対する懸念もあるとのこと。&lt;/p&gt;&#10;&lt;p&gt;対照的に、NASは彼が認識するいくつかの利点を持っています。その最大の利点はランニングコストの低さです。初期投資は必要ですが、その後の維持費はほとんどかかりません。さらに、NASは必要に応じて容量を追加することができ、大容量のデータを安心して保存することができます。そして、彼が重視するプライバシーもNASならば自分自身の手で守ることができます。&lt;/p&gt;&#10;&lt;p&gt;ただし、全てが順風満帆なわけではありません。NASを選択すると、データの共有に一工夫必要となる場合があります。彼自身も認識しているように、これは今後の課題の一つでしょう。&lt;/p&gt;&#10;&lt;h2 id="今後の展望"&gt;今後の展望&#10;&lt;/h2&gt;&lt;p&gt;彼の将来のプランについて語り始めると、その声からはわくわくするような期待感が伝わってきます。当面の間、彼はDropboxとNASを併用すると言います。Dropboxの利便性を手放すことなく、同時にNASのメリットを享受するこのスタンスは、彼の柔軟な思考を如実に表しています。しかし、それは彼が直面する一部の問題、例えばMacのSMBクライアントの問題が解決するまでの暫定的なもの。&lt;/p&gt;&#10;&lt;p&gt;最終的に彼が目指すのは、自分だけのプライベートクラウドを持つこと。これは彼自身のデータの世界を自由自在に操ることができる空間を指します。彼はデータを自由に保存し、いつでも自由に取り出すことができます。そしてそのデータを使って分析を行ったり、新しい発見をしたりと、好奇心を満たすための遊び場としても機能します。&lt;/p&gt;&#10;&lt;p&gt;このプライベートクラウドの構築は、彼にとって新たな挑戦の一歩となります。それはまさに、彼自身のデータ領域を広げ、新たな価値を創造するためのステップとなるでしょう。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;最初の語り口で笑ってしまった。なんだよ巨人Dropboxって。&lt;/p&gt;&#10;&lt;p&gt;ChatGPTのチャットが流れてしまって、どんな質問をしたか覚えてないんだけれど、とにかく「インタビューしてくれ」と「ブログにしてくれ」だね。インタビューの仕方は中々指示どおりしてくれない。終わりの合図はこっちですると言ったのに勝手に締めるし、一つずつ質問してくれと言ったそばから箇条書きで質問リスト並べてくるし。まぁ訂正すればリクエストには答えてくれるんだけどさ。&lt;/p&gt;&#10;&lt;p&gt;ただまぁ、けっこう自分の考えていることを深掘りするにはいいフレームワークかもしれないな、と思ったりもしたね。&lt;/p&gt;&#10;</description></item><item><title>【Macユーザー必見】右クリックから画像をwebpに瞬時に変換しよう！</title><link>https://ai.hack-le.com/mac-webp/</link><pubDate>Sun, 16 Jul 2023 14:13:24 +0900</pubDate><guid>https://ai.hack-le.com/mac-webp/</guid><description>&lt;p&gt;内容はタイトルのとおりで、クイックアクションを使ってwebpに変換するコマンドを作成するというもの。要はこれを作る。&lt;/p&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2023/07/a468cf58e75fa2612957a0d6740ebdf5.jpg"&gt;&lt;/p&gt;&#10;&lt;p&gt;これは普通に便利だよ。では以下、ChatGPT-4によるテンション高めの記事本文。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;こんにちは、今日はMacの便利な機能であるクイックアクションを使って、画像をwebp形式に変換する方法をご紹介します。この方法を使えば、画像ファイルを右クリックするだけで簡単にwebp形式に変換することができます。&lt;/p&gt;&#10;&lt;p&gt;手順は以下の通りです。&lt;/p&gt;&#10;&lt;h2 id="準備"&gt;準備&#10;&lt;/h2&gt;&lt;p&gt;今回の作業のための準備をしましょう。いくつかのツールを入れる必要があります。&lt;/p&gt;&#10;&lt;h3 id="homebrewのインストール"&gt;Homebrewのインストール&#10;&lt;/h3&gt;&lt;p&gt;まずはHomebrewをインストールします。HomebrewはMacでソフトウェアを簡単に管理するためのパッケージ管理システムです。既にインストールしてある方はこの手順をスキップしてください。ターミナルを開き、以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/bin/bash -c &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="libwebpのインストール"&gt;libwebpのインストール&#10;&lt;/h3&gt;&lt;p&gt;次に、Homebrewを使ってlibwebpをインストールします。libwebpはGoogleが開発した画像形式であるwebpへの変換ツールです。ターミナルで以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install webp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="クイックアクションの作成"&gt;クイックアクションの作成&#10;&lt;/h2&gt;&lt;p&gt;Automatorを開き、「新規ドキュメント」を作成します。「ドキュメントの種類」の選択画面が表示されたら、「クイックアクション」を選択します。選択したら、下記のような設定をしますので、手順を説明します。&lt;/p&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2023/07/7374f7834a56835f276a2c2bcaba8f00.jpg"&gt;&lt;/p&gt;&#10;&lt;p&gt;「ワークフローが受け取る現在の項目」の項目で「イメージファイル」を選択し、さらにその右隣の「検索対象」のドロップダウンから「Finder」を選択します。&lt;/p&gt;&#10;&lt;p&gt;左側のパネルから「ユーティリティ」カテゴリを開き、「シェルスクリプトを実行」を右側の空白領域にドラッグアンドドロップします。&lt;/p&gt;&#10;&lt;p&gt;シェルスクリプトアクションに以下のコマンドを入力します（「入力の引き渡し方法」は「引数として」に設定）。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; f in &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /usr/local/bin/cwebp &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -o &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;著者注記: あらかじめ &lt;code&gt;which cwebp&lt;/code&gt; でcwebpのパスを調べておく。 &lt;code&gt;/opt/homebrew/bin/cwebp&lt;/code&gt;にする必要があるかも。&lt;/p&gt;&#10;&lt;h2 id="クイックアクションの実行"&gt;クイックアクションの実行&#10;&lt;/h2&gt;&lt;p&gt;メニューバーの「ファイル」から「保存」を選び、クイックアクションに名前をつけて保存します。この名前がコマンドの名前になるため、「webpに変換」などのわかりやすい名前にしましょう。&lt;/p&gt;&#10;&lt;p&gt;これで準備は完了です。Finderから画像ファイルを右クリックすると、コンテクストメニューの「クイックアクション」の中に新しく作成したアクションが表示されます。選択すると、選択した画像ファイルがwebp形式に変換され、元の画像と同じ場所に保存されます。&lt;/p&gt;&#10;&lt;h2 id="注意点画質と元画像の削除について"&gt;注意点、画質と元画像の削除について&#10;&lt;/h2&gt;&lt;h3 id="元画像の削除"&gt;元画像の削除&#10;&lt;/h3&gt;&lt;p&gt;注意点として、このコマンドは元の画像ファイルを保持しつつ新しいwebpファイルを作成します。元の画像を削除したい場合は、上記のシェルスクリプトに&lt;code&gt;rm &amp;quot;$f&amp;quot;&lt;/code&gt;コマンドを追加します。これにより、変換後のwebpファイルが作成された後に元の画像が削除されます。&lt;/p&gt;&#10;&lt;p&gt;以下に修正したコードを示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; f in &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /usr/local/bin/cwebp &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -o &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rm &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは元のファイルを完全に削除するため、誤って重要なファイルを削除しないように十分注意してください。実行前にバックアップを取るなど、データの安全対策を忘れずに行ってください。&lt;/p&gt;&#10;&lt;h3 id="画像の品質"&gt;画像の品質&#10;&lt;/h3&gt;&lt;p&gt;また、出力されるwebp画像の品質はデフォルトの設定（75％）になります。品質設定を変更するには、上記のcwebpコマンドに-qオプションを追加します（例：-q 90）。&lt;/p&gt;&#10;&lt;p&gt;以上で、Macのクイックアクションを使って画像を簡単にwebpに変換する方法のご紹介を終えます。ぜひ試してみてください。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;有能。シェルスクリプトを交えつつAutomatorを使った完全なガイド。これはGoogle検索だと中々出てこない。&lt;/p&gt;&#10;&lt;p&gt;以下のような質問をした。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Macのクイックアクションで、画像をwebpに変換するアクションを作成したい！&lt;/li&gt;&#10;&lt;li&gt;素晴らしい。完璧だ。UIは日本語のほうがよかったが、そこは僕が補足しよう。 クイックアクションで画像ファイルを右クリックから手軽にwebpに変換できるようにする方法について、ブログ記事としてまとめてくれ&lt;/li&gt;&#10;&lt;li&gt;元の画像を削除したい場合のコードについても書いたほうがいいな。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;解説のUIが思いっきり英語だったので、僕のほうで直すといったところ、なんだか日本語化しようと頑張っていたが、結果間違っていたのでそこは僕が修正した。相変わらずディテールを間違えるChatGPT。こうして人間の仕事は微調整になっていくのか……。&lt;/p&gt;&#10;</description></item><item><title>AWSアカウントIDを確認する複数の方法</title><link>https://ai.hack-le.com/aws-id/</link><pubDate>Sun, 16 Jul 2023 03:12:33 +0900</pubDate><guid>https://ai.hack-le.com/aws-id/</guid><description>&lt;p&gt;タイトルのとおりなんだが、AWSアカウントIDをしばしば失念して、どうやって調べたらいいんだっけ？と思ってChatGPT-4に聞いた。聞いたら答えてくれるんだが、一番いい方法をなかなか教えてくれなかった。ChatGPTはそういうところある。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;こんにちは、AWSユーザーの皆さん。本日は、AWSアカウントIDを確認する方法についていくつか紹介します。一つはAWS CLIを用いる方法、もう一つはAWS Management Consoleを利用する方法です。さらに、CLIの中でも特に効率的な方法を一つご紹介します。&lt;/p&gt;&#10;&lt;h2 id="コンソールからのログイン"&gt;コンソールからのログイン&#10;&lt;/h2&gt;&lt;p&gt;まずAWS Management ConsoleからアカウントIDを確認する方法を見てみましょう。以下の手順になります：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;AWS Management Consoleにログインします。&lt;/li&gt;&#10;&lt;li&gt;右上のナビゲーションバーにある自分のアカウント名またはユーザー名をクリックします。&lt;/li&gt;&#10;&lt;li&gt;ドロップダウンメニューから&amp;quot;My Security Credentials&amp;quot;（または&amp;quot;セキュリティ資格情報&amp;quot;）を選択します。&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;Account details&amp;rdquo;（または&amp;quot;アカウント詳細&amp;quot;）セクションを展開すると、アカウントIDが表示されます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;しかしこの方法は、すでにAWS Management Consoleにログインしていることが前提となっています。つまり、ログイン前の状況では利用できないという制約があります。&lt;/p&gt;&#10;&lt;h2 id="aws-stsによる取得"&gt;AWS STSによる取得&#10;&lt;/h2&gt;&lt;p&gt;AWS CLIから直接アカウントIDを取得したい場合には、AWS Security Token Service（STS）の &lt;code&gt;get-caller-identity&lt;/code&gt; コマンドが非常に便利です。次のように実行します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、以下のような出力が表示されます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserId&amp;#34;: &amp;#34;AIDAJDPLRKLG7UEXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Account&amp;#34;: &amp;#34;123456789012&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/Alice&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ldquo;Account&amp;quot;フィールドがあなたのAWSアカウントIDです。&lt;/p&gt;&#10;&lt;p&gt;この&lt;code&gt;get-caller-identity&lt;/code&gt;コマンドは、ログインを必要とせず、コマンドラインから直接アカウントIDを取得できるため、スクリプトの自動化や複数のAWSアカウントを管理する際に非常に便利です。&lt;/p&gt;&#10;&lt;p&gt;いずれの方法を選択するにせよ、AWSのセキュリティ資格情報（アクセスキーとシークレットアクセスキー）は適切に管理し、他人に漏れないように注意する必要があります。それでは、引き続きAWSの探求を楽しんでください。質問や意見がありましたら、お気軽にコメント欄からどうぞ！&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;やけにフレンドリーな文体でなんか笑う。&lt;/p&gt;&#10;&lt;p&gt;それはそれとして、この回答はストレートにもらえていない。何故か最初に &lt;code&gt;aws iam get-user&lt;/code&gt; を使うやり方を勧めてきたんだよ。確かにそれでも取得できるんだけれど、&lt;code&gt;aws sts&lt;/code&gt;を使った出力のほうが断然スマートだった。代替え案はあるか聞いたら教えてくれたんだけど……危ないなぁ。他にいい案はないか、聞くほうがいいんだな。勉強になった。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;AWSのアカウントIDをCLIで知る方法はある？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ここでaws iam get-userを出してきた&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;うまくいった。備忘録のために、これをブログの記事風にまとめてくれ。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;てっきりこれで終わるところだった。騙されるところだった&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;ありがとう。ちなみに他にAWSアカウントIDを確認する方法はあるかな？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ふと気になって聞いてみた&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;aws sts get-caller-identity が一番いいな。 コンソールのほうは、ログインしないとわからないから、ログインする前だと残念ながら金庫の中の鍵なんだよねぇ。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;てめー最初からそっち言えよこんにゃろーと思いつつ&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="5"&gt;&#10;&lt;li&gt;ここまでの議論をブログ記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;ChatGPTは役人と思って接しなければならないと改めて感じた。ちなみに記事もそこそこ手を入れている。うーん、質問力が試される……。&lt;/p&gt;&#10;</description></item><item><title>WSL2でMacのようにクリップボードを操作する方法</title><link>https://ai.hack-le.com/wsl2-mac-clipboard/</link><pubDate>Sun, 16 Jul 2023 00:52:55 +0900</pubDate><guid>https://ai.hack-le.com/wsl2-mac-clipboard/</guid><description>&lt;p&gt;Macだとpbcopyやpbpasteといったコマンドでクリップボードの内容をターミナル上で扱うことができて、これが非常に便利。Windowsでも同じことができないか、ChatGPT-4に聞いたところ非常にうまくいったので、ブログ記事としてまとめさせた。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;Windows Subsystem for Linux 2（WSL2）は、Windows上でLinuxを動作させることができる強力なツールです。しかし、Macユーザーが利用できる便利な&lt;code&gt;pbcopy&lt;/code&gt;と&lt;code&gt;pbpaste&lt;/code&gt;コマンドのような、クリップボードに直接アクセスする機能がデフォルトではありません。この記事では、WSL2でこれらのコマンドを模倣する方法を解説します。&lt;/p&gt;&#10;&lt;h2 id="windowsのクリップボードにコピー"&gt;Windowsのクリップボードにコピー&#10;&lt;/h2&gt;&lt;p&gt;WSL2からWindowsのクリップボードにコピーするには、Windows側の&lt;code&gt;clip.exe&lt;/code&gt;コマンドを利用します。例えば次のようにします:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;テキスト&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; clip.exe&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="windowsのクリップボードからペースト"&gt;Windowsのクリップボードからペースト&#10;&lt;/h2&gt;&lt;p&gt;逆に、WindowsのクリップボードからWSL2にペーストするには、&lt;code&gt;powershell.exe&lt;/code&gt;を利用します:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;powershell.exe -command &lt;span class="s1"&gt;&amp;#39;Get-Clipboard&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="コマンドを短くする"&gt;コマンドを短くする&#10;&lt;/h2&gt;&lt;p&gt;これらのコマンドは有用ですが、特にペーストの方は長く、打つのが面倒かもしれません。それを解決するために、&lt;code&gt;pbcopy&lt;/code&gt;と&lt;code&gt;pbpaste&lt;/code&gt;というエイリアスを定義します。&lt;/p&gt;&#10;&lt;h3 id="bashの場合"&gt;bashの場合&#10;&lt;/h3&gt;&lt;p&gt;bash シェルを使っている場合、&lt;code&gt;.bashrc&lt;/code&gt; ファイルに以下のエイリアスを追加します:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;pbcopy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;clip.exe&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;pbpaste&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;powershell.exe -command Get-Clipboard&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;そして、ターミナルを再起動するか、以下のコマンドを実行して新しいエイリアスを利用可能にします:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで、Macのように &lt;code&gt;pbcopy&lt;/code&gt; と &lt;code&gt;pbpaste&lt;/code&gt; コマンドを使用することができます。&lt;/p&gt;&#10;&lt;h3 id="fishの場合"&gt;fishの場合&#10;&lt;/h3&gt;&lt;p&gt;Fish shellでは、関数として定義して、&lt;code&gt;config.fish&lt;/code&gt;ファイルに保存することで、同様の機能を実現できます。&lt;/p&gt;&#10;&lt;p&gt;まず、Fish shellで新しい関数を作成します:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; -n &lt;span class="nv"&gt;$argv&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; clip.exe&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;end&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; pbpaste&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; powershell.exe -command &lt;span class="s1"&gt;&amp;#39;Get-Clipboard&amp;#39;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;end&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;次に、これらの関数を保存します。以下のコマンドは、作成した関数を &lt;code&gt;~/.config/fish/functions/&lt;/code&gt; ディレクトリに保存します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;funcsave pbcopy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;funcsave pbpaste&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上の手順で、&lt;code&gt;pbcopy&lt;/code&gt;と&lt;code&gt;pbpaste&lt;/code&gt;の機能をFish shellで使用できるようになります。新たなシェルセッションでもこれらの関数が使用可能になるよう、手動で定義するのではなく、&lt;code&gt;funcsave&lt;/code&gt; コマンドを使って保存することが重要です。&lt;/p&gt;&#10;&lt;h2 id="結論"&gt;結論&#10;&lt;/h2&gt;&lt;p&gt;これにより、WSL2でもMacのようにクリップボードを操作することが可能になります。この機能を利用すれば、シェルスクリプトやコマンドラインツールから直接クリップボードにアクセスすることができ、作業の効率を上げることができます。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;これでWSL2でも&lt;code&gt;pbcopy&lt;/code&gt;や&lt;code&gt;pbpaste&lt;/code&gt;といったコマンドを使えるようになった。pbcopyで一行改行ができるのが少し気になるが……。まぁでもこれは便利だね。&lt;/p&gt;&#10;&lt;p&gt;以下、質問した内容。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Macではpbcoyやpbpasteでクリップボードの内容をターミナルで利用できますが、WindowsのWSL2で同じようなことはできませんか&lt;/li&gt;&#10;&lt;li&gt;いいね。しかし、clip.exeはいいがペーストのほうはコマンドが長すぎる。&lt;/li&gt;&#10;&lt;li&gt;最高だ。完璧に&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;まちがって途中で送信してしまった&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;それでは、この素晴らしい方法を、いつでも思い出して使えるように、あるいは他の人もできるように、ブログ記事としてまとめてくれ。&lt;/li&gt;&#10;&lt;li&gt;fishだとどうなる？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;今回は記事の方もあまり手直ししていない。&lt;/p&gt;&#10;</description></item><item><title>WSL2のUbuntuでPNGをWebPに変換する</title><link>https://ai.hack-le.com/wsl-png-web/</link><pubDate>Fri, 14 Jul 2023 00:11:50 +0900</pubDate><guid>https://ai.hack-le.com/wsl-png-web/</guid><description>&lt;p&gt;WSL2でImageMagickを使ってpngをwebpにしようとしたところ、エラーが出た。ChatGPT-4に聞いたところ、即座に適切な答えが返ってきて感動した。&lt;/p&gt;&#10;&lt;p&gt;なのでそれを記事にしてもらったところ、pngをwebpに変換するという、エラー対応よりも汎用的な記事になった。エラーメッセージも本文中にあるし、こちらのほうが記事としてもよさそう。やるなChatGPT。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;本記事では、Windows Subsystem for Linux (WSL2) 上の Ubuntu 環境で PNG 画像を WebP 形式に変換する方法を説明します。このプロセスは、ImageMagick の &lt;code&gt;convert&lt;/code&gt; コマンドと Google の &lt;code&gt;cwebp&lt;/code&gt; ツールを使用します。&lt;/p&gt;&#10;&lt;h2 id="必要なツールのインストール"&gt;必要なツールのインストール&#10;&lt;/h2&gt;&lt;p&gt;まずは必要なツールをインストールしましょう。今回は、画像変換ツールの ImageMagick と WebP エンコーダの &lt;code&gt;cwebp&lt;/code&gt; を使用します。&lt;/p&gt;&#10;&lt;p&gt;ImageMagick は以下のコマンドでインストールできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install imagemagick&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;次に、WebP エンコーダの &lt;code&gt;cwebp&lt;/code&gt; をインストールします。&lt;code&gt;cwebp&lt;/code&gt; は libwebp パッケージの一部として提供されています。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install webp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで必要なツールのインストールは完了です。&lt;/p&gt;&#10;&lt;h2 id="画像の変換"&gt;画像の変換&#10;&lt;/h2&gt;&lt;p&gt;画像の変換は非常に簡単です。以下のように &lt;code&gt;convert&lt;/code&gt; コマンドを使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;convert input.png output.webp&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで &lt;code&gt;input.png&lt;/code&gt; は変換したい PNG 画像のパス、&lt;code&gt;output.webp&lt;/code&gt; は出力する WebP 画像のパスを指定します。&lt;/p&gt;&#10;&lt;p&gt;ただし、これを初めて実行すると、次のようなエラーが出ることがあります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;convert-im6.q16: delegate failed `&amp;#39;cwebp&amp;#39; -quiet %Q &amp;#39;%i&amp;#39; -o &amp;#39;%o&amp;#39;&amp;#39; @ error/delegate.c/InvokeDelegate/1919.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このエラーは、&lt;code&gt;convert&lt;/code&gt; コマンドが &lt;code&gt;cwebp&lt;/code&gt; ツールを使おうとしたが見つからなかったために発生します。これは通常、&lt;code&gt;cwebp&lt;/code&gt; がシステムにインストールされていないか、パスが正しく設定されていないことを意味します。この問題は前述の手順で &lt;code&gt;cwebp&lt;/code&gt; をインストールすることで解決します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;今回は、WSL2 の Ubuntu 環境で PNG 画像を WebP 形式に変換する方法を見てきました。必要なツールのインストールから、実際の画像変換、そして一般的なエラーの解決方法までを網羅しました。これにより、あなたのシステムでも WebP 画像の生成が可能になり、WebP の圧縮効率と品質の良さを最大限に活用することができます。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;速攻で解決して感動した。以下質問。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;convertコマンドでpngをwebpに変換しようとしたら、エラーが出た。 convert-im6.q16: delegate failed `&amp;lsquo;cwebp&amp;rsquo; -quiet %Q &amp;lsquo;%i&amp;rsquo; -o &amp;lsquo;%o&amp;rsquo;&amp;rsquo; @ error/delegate.c/InvokeDelegate/1919.&lt;/li&gt;&#10;&lt;li&gt;WSL2のUbuntuで実行したところ、うまくいったよ。ありがとう。 備忘録のために、ここまでのことを、ブログの記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;質問まったくしていない。&lt;/p&gt;&#10;&lt;p&gt;単一質問のシンプルなもので、ChatGPTが即座に答えてくれるうえに、コマンドなので誰でも評価できる以上、ブログ記事にする意味はあるのか？という疑義はあるが、自分の備忘録も兼ねているので。常にChatGPTが使える状況でもないし、ChatGPTもどうなるかわからないし。&lt;/p&gt;&#10;</description></item><item><title>Boto3のTypeDeserializerを使用してDynamoDB Streamsイベントをパースする</title><link>https://ai.hack-le.com/boto3-typedeserializer-dynamodb-streams/</link><pubDate>Thu, 06 Jul 2023 22:12:04 +0900</pubDate><guid>https://ai.hack-le.com/boto3-typedeserializer-dynamodb-streams/</guid><description>&lt;p&gt;DynamoDB Streamのパース、ずっと自前でやっていたんだが、実はライブラリでデシリアライザが用意されていることを「&lt;a class="link" href="https://dev.classmethod.jp/articles/convert-dynamodb-json-to-python-dict-by-boto3/" target="_blank" rel="noopener"&#10; &gt;DynamoDB JSONの型変換をboto3だけで行ってみる | DevelopersIO&lt;/a&gt;」で知った。。。これを使うとDynamoDB Streamのパースも楽にできる。&lt;/p&gt;&#10;&lt;p&gt;テストデータとセットであると便利に思ったので、ChatGPT-4に聞いてみた。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;Boto3のTypeDeserializerは、DynamoDBのデータ型をPythonの標準のデータ型に変換するのに役立ちます。これは、DynamoDB Streamsのイベントを処理する際に特に便利です。この記事では、TypeDeserializerの基本的な使い方と、それを使用してDynamoDB Streamsイベントをパースする方法について説明します。&lt;/p&gt;&#10;&lt;h2 id="typedeserializerの基本"&gt;TypeDeserializerの基本&#10;&lt;/h2&gt;&lt;p&gt;TypeDeserializerクラスは、DynamoDBのレスポンスをパースするための便利なツールです。これはDynamoDBからのレスポンスをPythonの標準的なデータ型に変換します。以下に基本的な使用方法を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deserializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# DynamoDBのデータ&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dynamodb_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Hello, world!&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# データをデシリアライズ&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deserialized_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dynamodb_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deserialized_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# &amp;#39;Hello, world!&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここでは、DynamoDBの文字列型（&amp;lsquo;S&amp;rsquo;）をPythonの文字列にデシリアライズしています。&lt;/p&gt;&#10;&lt;p&gt;なお、DynamoDBの数値データ型（&amp;lsquo;N&amp;rsquo;）は、Boto3のTypeDeserializerを使用してデシリアライズされるとき、Pythonの&lt;code&gt;decimal.Decimal&lt;/code&gt;型になります。&lt;/p&gt;&#10;&lt;p&gt;これはDynamoDBが数値を浮動小数点数として保存し、それがそのままの精度で保存されることを保証するためです。Pythonの標準的な&lt;code&gt;int&lt;/code&gt;や&lt;code&gt;float&lt;/code&gt;型を使用すると、特に大きな数値や非常に小さな数値の場合に精度が失われる可能性があります。そのため、&lt;code&gt;decimal.Decimal&lt;/code&gt;型が使用されます。&lt;/p&gt;&#10;&lt;h2 id="dynamodb-streamsイベントのパース"&gt;DynamoDB Streamsイベントのパース&#10;&lt;/h2&gt;&lt;p&gt;DynamoDB Streamsイベントは、テーブルに変更があったときに発行されます。これらのイベントには、変更前後の項目の詳細やイベントの種類（INSERT、MODIFY、REMOVE）など、役立つ情報が含まれています。&lt;/p&gt;&#10;&lt;p&gt;以下は、TypeDeserializerを使用してDynamoDB Streamsイベントをパースする例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_dynamodb_stream_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Records&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dynamodb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 変更前の項目をパース&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;OldImage&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;old_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OldImage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;old_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 変更後の項目をパース&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NewImage&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NewImage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Event Name: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;eventName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Old Image: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;old_image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;New Image: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この関数は、DynamoDB Streamsイベントの各レコードの&amp;quot;OldImage&amp;quot;と&amp;quot;NewImage&amp;quot;をパースしてPythonのデータ型に変換します。これにより、変更前後の項目データを簡単に利用することができます。&lt;/p&gt;&#10;&lt;p&gt;なお、DynamoDB Streamのイベント例は以下です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Records&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventID&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;INSERT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventVersion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSource&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:dynamodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;awsRegion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dynamodb&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Keys&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;NewImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;New item!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;StreamViewType&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;NEW_AND_OLD_IMAGES&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SequenceNumber&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;111&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SizeBytes&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSourceARN&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventID&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MODIFY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventVersion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSource&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:dynamodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;awsRegion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dynamodb&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Keys&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;NewImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;This item has changed&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;OldImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;New item!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;StreamViewType&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;NEW_AND_OLD_IMAGES&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SequenceNumber&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;222&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SizeBytes&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSourceARN&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventID&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;REMOVE&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventVersion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSource&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:dynamodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;awsRegion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dynamodb&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Keys&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;OldImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;This item has changed&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;StreamViewType&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;NEW_AND_OLD_IMAGES&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SequenceNumber&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;333&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SizeBytes&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;38&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSourceARN&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上が、Boto3のTypeDeserializerを使用してDynamoDB Streamsイベントをパースする方法です。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;テストデータを出してくれるのが神。&lt;/p&gt;&#10;&lt;p&gt;以下がChatGPT-4にした質問。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;boto3のTypeDeserializerの使い方を教えて&lt;/li&gt;&#10;&lt;li&gt;DynamoDB Streamのeventをパースするのにも使える？&lt;/li&gt;&#10;&lt;li&gt;DynamoDB Streamのテストデータを出して&lt;/li&gt;&#10;&lt;li&gt;ここまでのことを記事としてまとめてください。&lt;/li&gt;&#10;&lt;li&gt;（追加）このデシリアライザを使うと、数値はDecimalになりますか、それともintになりますか、それともfloatになりますか？&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;最初にある程度正解知ってるからよかった。&lt;/p&gt;&#10;</description></item><item><title>Dockerイメージの削除とメンテナンス</title><link>https://ai.hack-le.com/docker-prune/</link><pubDate>Thu, 06 Jul 2023 12:30:33 +0900</pubDate><guid>https://ai.hack-le.com/docker-prune/</guid><description>&lt;p&gt;ビルドのためだけにDockerを使っているライトユーザなので、不必要に圧迫するDockerイメージの削除ってどうやるんだっけ？といつも調べることになる。ChatGPTに聞きつつメモ。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;Dockerを使用すると、非常に便利な一方で、多数のイメージが生成され、管理が難しくなる可能性があります。これらのイメージを適切に管理するための基本的なアプローチを以下に示します。&lt;/p&gt;&#10;&lt;h2 id="dockerイメージの削除"&gt;Dockerイメージの削除&#10;&lt;/h2&gt;&lt;p&gt;Dockerイメージの削除は以下のコマンドで行うことができます：&lt;/p&gt;&#10;&lt;h3 id="特定のイメージを削除する"&gt;特定のイメージを削除する&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker rmi &amp;lt;IMAGE_ID_OR_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドで、指定したイメージIDまたは名前のDockerイメージを削除できます。&lt;/p&gt;&#10;&lt;h3 id="未使用のdockerイメージを一括削除する"&gt;未使用のDockerイメージを一括削除する&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker image prune -a&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドを使用すると、未使用のすべてのDockerイメージが削除されます。 &amp;lsquo;-a&amp;rsquo;フラグは、タグのないイメージだけでなく、どのコンテナにも使われていないイメージも削除します。&lt;/p&gt;&#10;&lt;h2 id="削除するdockerイメージの選択"&gt;削除するDockerイメージの選択&#10;&lt;/h2&gt;&lt;p&gt;重要なイメージを誤って削除しないように、どのイメージを削除するべきか判断するための一般的なアプローチは次の通りです。&lt;/p&gt;&#10;&lt;p&gt;すべてのDockerイメージを表示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;リストから削除するイメージのIDまたは名前をメモします。&lt;/p&gt;&#10;&lt;p&gt;個々のイメージがどのコンテナで使われているか確認します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker ps -a &lt;span class="p"&gt;|&lt;/span&gt; grep &amp;lt;IMAGE_ID_OR_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;イメージが使用されていないか、またはそのイメージを使用しているコンテナがもはや必要でないと判断した場合、そのイメージを削除します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker rmi &amp;lt;IMAGE_ID_OR_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ただし、これらの手順は結構手間がかかるため、自動化したい場合や、不要なイメージが明らかな場合には、&lt;code&gt;docker image prune -a&lt;/code&gt; のようなコマンドを使って、未使用のイメージを一括削除することができます。&lt;/p&gt;&#10;&lt;h2 id="ユースケースに基づく管理方法"&gt;ユースケースに基づく管理方法&#10;&lt;/h2&gt;&lt;p&gt;使用方法によっては、一括削除がより実用的な選択となることもあります。例えば、常に新しいイメージを作成し、古いイメージを使用しない場合や、AWS SAMなどのビルドのためだけにDockerを使用している場合などです。これらの状況では、&lt;code&gt;docker image prune-a&lt;/code&gt;や&lt;code&gt;docker system prune -a&lt;/code&gt;といったコマンドを定期的に実行することで、ディスクスペースの解放と新たなビルドのためのスペース確保が可能です。&lt;/p&gt;&#10;&lt;p&gt;ただし、これらのコマンドは一括削除を行うため、非常に便利ですが、削除対象の理解と注意が必要です。どのような状況でも、定期的なバックアップや、重要なデータの保存といった基本的な対策を怠らないようにしましょう。&lt;/p&gt;&#10;&lt;p&gt;以上、Dockerイメージの管理について簡単にまとめました。これらの手順を実践することで、Dockerイメージの管理を効率的かつ安全に行うことができます。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;ChatGPT-4にした質問は以下。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;dockerで不要なイメージを削除したい&lt;/li&gt;&#10;&lt;li&gt;削除するイメージが必要なものでないことを確認するにはどうしたらよい？&lt;/li&gt;&#10;&lt;li&gt;理想的には、あらかじめすべてのイメージを出力して、個別に判断して削除するべき、ということになるか&lt;/li&gt;&#10;&lt;li&gt;なるほど。しかし、私は主にDockerはAWS SAMなどのビルドのためだけに利用している。つまり、常時稼働しているイメージはない。たとえ削除してもまた作ればよいだけで、害はあまりない。 こうした場合は、日常の手間を考えると一括削除も悪くない選択に思える。&lt;/li&gt;&#10;&lt;li&gt;ここまでの議論を記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>WordPressのエディタ選択: Gutenbergとクラシックエディタの存在理由と選択ガイド</title><link>https://ai.hack-le.com/wordpress-gutenberg/</link><pubDate>Fri, 30 Jun 2023 00:45:50 +0900</pubDate><guid>https://ai.hack-le.com/wordpress-gutenberg/</guid><description>&lt;p&gt;これは私がクラシックエディタの存在意義についてChatGPT-4に書かせたものである。私自身は複数のブログを運営しており、Gutenbergをメインにしているものもあれば、クラシックエディタをメインにしているものもある。どちらにも良いところと悪いところがあるわけだが、基本的には新しいエディタであるGutenbergが推奨される。というか、Gutenbergが出てもう何年もたっているのに、未だにクラシックエディタは健在である。それはいったいぜんたいどういうことだ、ということについての記事である。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;WordPressユーザーにとって、記事やページの作成と編集は日々の重要なタスクの一つです。そのため、使用するエディタの選択は、作業の効率性、使いやすさ、そして最終的なコンテンツの品質に大きな影響を与えます。WordPressでは、現在、二つの主要なエディターが提供されています: Gutenbergとクラシックエディタ。しかし、これらの違いとどちらを選ぶべきかは一見すると明確ではありません。ここでは、両者の特性を詳しく見ていき、どちらのエディタがあなたに適しているかを判断するためのガイドを提供します。&lt;/p&gt;&#10;&lt;h2 id="gutenbergとクラシックエディタの違い"&gt;Gutenbergとクラシックエディタの違い&#10;&lt;/h2&gt;&lt;p&gt;まず最初に、それぞれのエディタの特性と機能を理解することが重要です。&lt;/p&gt;&#10;&lt;p&gt;Gutenbergは、ブロックベースのエディタで、視覚的なレイアウトとデザインに重点を置いています。それは特に、画像、ビデオ、カラムレイアウトなどを頻繁に使用するユーザーにとって有用です。視覚的なエディタとして、ユーザーは自由にブロックを移動、編集、または削除することができ、より直感的なビジュアル編集体験を提供します。&lt;/p&gt;&#10;&lt;p&gt;一方、クラシックエディタはより伝統的なWordPressエディタで、テキストエディタと視覚エディタの間で切り替える選択肢があります。これはテキストベースのコンテンツとHTMLコードを直接編集する能力を必要とする人々にとっては便利な機能かもしれません。&lt;/p&gt;&#10;&lt;h2 id="なぜクラシックエディタは依然として存在しているのか"&gt;なぜクラシックエディタは依然として存在しているのか&#10;&lt;/h2&gt;&lt;p&gt;それぞれのエディタには独自の利点があり、WordPressユーザーの間でそれぞれ異なるニーズを満たしています。Gutenbergは多くの点で魅力的なエディタですが、すべてのユーザーや状況に対して最適とは限りません。その一部を以下に挙げます。&lt;/p&gt;&#10;&lt;h3 id="テキストヘビーなブログ"&gt;テキストヘビーなブログ&#10;&lt;/h3&gt;&lt;p&gt;Gutenbergは視覚的な要素とレイアウトが多いサイトに最適化されています。しかし、主にテキストベースのコンテンツを提供するブログや、コードスニペットや引用などの特定のテキスト要素を頻繁に使用するウェブサイトでは、クラシックエディタの方がより直感的で使いやすい場合があります。&lt;/p&gt;&#10;&lt;h3 id="高度なカスタマイゼーションの必要性"&gt;高度なカスタマイゼーションの必要性&#10;&lt;/h3&gt;&lt;p&gt;Gutenbergは便利なブロックを提供していますが、それらのブロックのカスタマイゼーションは限定的です。HTMLやCSSのようなウェブ言語に精通していて、独自のカスタマイゼーションを高度に適用したいユーザーにとっては、クラシックエディタの方が直接的なコード編集の能力を提供するため、より魅力的な選択肢となるかもしれません。&lt;/p&gt;&#10;&lt;h3 id="特定のプラグインやテーマの依存"&gt;特定のプラグインやテーマの依存&#10;&lt;/h3&gt;&lt;p&gt;一部のプラグインやテーマは、Gutenbergではなくクラシックエディタに最適化されているか、または両方をサポートしていません。したがって、これらのプラグインやテーマに依存している場合、Gutenbergの使用は制限される可能性があります。&lt;/p&gt;&#10;&lt;p&gt;ただし、古いプラグインやテーマには、セキュリティなどの観点で別の問題を抱えていることにも留意すべきです。&lt;/p&gt;&#10;&lt;h3 id="学習曲線"&gt;学習曲線&#10;&lt;/h3&gt;&lt;p&gt;最後に、長年にわたりWordPressを使用してきたユーザーの中には、クラシックエディタの使いやすさと見覚えのあるインターフェースのほうが好ましいを感じられる人もいるでしょう。新しいシステムを学ぶことなく、すぐに編集作業を開始できることは、継続的にコンテンツを提供するために重要な要素です。&lt;/p&gt;&#10;&lt;h2 id="新規参加者にとってなぜgutenbergがおすすめなのか"&gt;新規参加者にとって、なぜGutenbergがおすすめなのか&#10;&lt;/h2&gt;&lt;p&gt;これらの理由にもかかわらず、新規のWordPressユーザーに対しては、まずGutenbergを試すことをお勧めします。その理由は、Gutenbergが現在のデフォルトのエディタであり、今後のアップデートと新機能のサポートが続くと考えられるからです。&lt;/p&gt;&#10;&lt;p&gt;GutenbergはWordPressの未来のデザインと機能の方向性を示しています。ブロックベースの設計は、編集体験をより直感的で視覚的にするだけでなく、柔軟性と拡張性も提供します。ユーザーは個々のブロックを使ってページを自由に設計し、各ブロックを個別にカスタマイズすることができます。&lt;/p&gt;&#10;&lt;p&gt;さらに、新機能や改善はまずGutenbergに導入され、新しいテーマやプラグインはGutenbergとの互換性を保証する傾向があります。これは、Gutenbergを学ぶことが、最新のWordPress機能を活用するための重要なステップであることを示しています。&lt;/p&gt;&#10;&lt;h2 id="最終的な選択はユーザーのニーズによる"&gt;最終的な選択はユーザーのニーズによる&#10;&lt;/h2&gt;&lt;p&gt;最終的には、どのエディタを選ぶべきかは、その人が何を求めているか、どのようなスキルや経験を持っているかによります。したがって、最適なエディタを見つけるためには、両方のエディタを試し、自分のニーズと作業フローに最も適しているものを選ぶことをお勧めします。&lt;/p&gt;&#10;&lt;p&gt;しかし、今後のことを考えると、新規のWordPressユーザーは、まずGutenbergを試すことを強くお勧めします。現在のデフォルトのエディタとして、そしてWordPressの未来のデザインと機能の方向性を示しているためです。クラシックエディタはまだ有効な選択肢であり続けますが、新しいユーザーはGutenbergに触れ、その機能と可能性を試すことで、最新のWordPress機能を最大限に活用するための基盤を築くことができます。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;僕はクラシックエディタとGutenbergの両方を使っている。このChatGPT-4の回答は、概ね悪くないものだと思う（まぁそのように誘導したとも言えるが…）。&lt;/p&gt;&#10;&lt;p&gt;以下のような質問をした。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;WordPressのGutenbergはクラシックエディタと比べた時、すべての人にとって推奨されるエディタだと言えるか。&lt;/li&gt;&#10;&lt;li&gt;シンプルな編集体験を求めるのは、具体的にどんな人か&lt;/li&gt;&#10;&lt;li&gt;私自身、Gutenbergをメインで使っているブログとクラシックエディタをメインで使っているブログに分かれている。テキストベースのブログでクラシックエディタを今も使っており、実際、機能的にもクラシックエディタのほうが優れていると感じることが多い。Gutenbergではタブキーで箇条書きのインデントを下げるといった、通常テキストエディタに期待されるような機能もなかったりする。 2つの形式をサポートするのはWordPressにとっても負荷が大きいと思うが、実際的に両方に向き不向きがあると感じる。Gutenbergに統一されることはあるのだろうか。&lt;/li&gt;&#10;&lt;li&gt;これからWordPressを始めようという人に、あえてクラシックエディタを勧める理由はあるだろうか。それとも、たとえテキストベースのブログであったとしても、今後のことを考えると、総合的にGutenbergを勧めるべきか。&lt;/li&gt;&#10;&lt;li&gt;ここまでの話を、長くなってもよいのでしっかりとした記事としてまとめてください。特に、今でもクラシックエディタがなくならない理由には必ず触れてください。そのうえでなお、新規参加者はまずGutenbergに触れたほうがよいのは何故かについても書いてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;ポイントとして、最初の質問で「すべての」という修飾を入れた。普通に聞けばChatGPT-4がGutenbergを勧めるのは明らかだったからだ。しかし、ChatGPTは「すべて」について語ることを避ける。そこで、「すべての人に勧められるか」を聞いて、勧められないパターンについて言及させた感じだ。&lt;/p&gt;&#10;&lt;p&gt;まぁ、僕自身もこれから始める人がわざわざクラシックエディタから選ぶ必要はないかなと思う。とはいえ、クラシックエディタで既にサイトを運営していてかつ、テキスト主体のブログの人が、あえてGutenbergに乗り換える理由も薄いだろう。&lt;/p&gt;&#10;</description></item><item><title>無料ブログプラットフォームとWordPress: 所有権がもたらす影響とその重要性</title><link>https://ai.hack-le.com/blog-wordpress/</link><pubDate>Tue, 27 Jun 2023 01:31:32 +0900</pubDate><guid>https://ai.hack-le.com/blog-wordpress/</guid><description>&lt;p&gt;デジタル時代において、オンラインでの情報発信は個々人だけでなく、ビジネスにとっても不可欠な要素となりました。そのためにはブログやウェブサイトが重要なツールとなりますが、その運営方法やプラットフォーム選びについて迷うことは少なくありません。この記事では、無料のブログプラットフォームとWordPressの違い、特に「所有権」の観点からその違いがもたらす影響について掘り下げていきます。&lt;/p&gt;&#10;&lt;h2 id="無料ブログプラットフォームとは"&gt;無料ブログプラットフォームとは&#10;&lt;/h2&gt;&lt;p&gt;無料のブログプラットフォーム、例えばBloggerやTumblrなどは、非常に手軽に始めることができるのが大きな特徴です。多くのテンプレートや基本的なカスタマイズオプションが提供されており、技術的な知識がほとんどなくてもブログの運営を始めることができます。一方で、その手軽さの裏には所有権の制限や機能の制約があります。&lt;/p&gt;&#10;&lt;h2 id="wordpressとは"&gt;WordPressとは&#10;&lt;/h2&gt;&lt;p&gt;WordPressは世界で最も広く使用されているコンテンツ管理システム（CMS）の一つで、特に自己ホストのWordPress.orgは、ユーザーに高度なカスタマイズ性と所有権を提供します。しかし、その一方で、一定の技術的知識や初期設定、メンテナンスが必要となります。&lt;/p&gt;&#10;&lt;h2 id="所有権とは"&gt;所有権とは&#10;&lt;/h2&gt;&lt;p&gt;所有権とは、あなたのウェブサイトとそのすべてのコンテンツを完全に制御する能力を指します。これは自分のサイトのデザイン、機能、SEO設定、データの管理など、ウェブサイト全体に対する絶対的な権利を含んでいます。WordPressを使用すれば、これら全てを自由自在にコントロールすることが可能です。&lt;/p&gt;&#10;&lt;h2 id="所有権の重要性"&gt;所有権の重要性&#10;&lt;/h2&gt;&lt;p&gt;所有権は、ウェブサイトの長期的な成功と成長に対する重要な要素です。それはサイトの見た目や機能を自分のニーズに合わせて調整できる自由度、SEOの最適化による訪問者の増加、そしてブランド価値の確立に寄与します。さらに、モネタイズの選択肢を広げることも可能にします。&lt;/p&gt;&#10;&lt;h2 id="無料ブログプラットフォームとwordpressの選択"&gt;無料ブログプラットフォームとWordPressの選択&#10;&lt;/h2&gt;&lt;p&gt;それぞれのプラットフォームにはメリットとデメリットがあります。無料のブログプラットフォームは初心者に優しく、すぐにブログを始めることができます。一方、WordPressは高度なカスタマイズや機能、所有権を提供しますが、そのための一定の技術的知識や運用コスト、メンテナンスが必要です。そのため、どちらを選ぶべきかはあなたのニーズや目標によります。&lt;/p&gt;&#10;&lt;h2 id="wordpressへの移行を考えるタイミング"&gt;WordPressへの移行を考えるタイミング&#10;&lt;/h2&gt;&lt;p&gt;カスタマイズの制限に直面したとき、SEOやマーケティングの必要性を感じたとき、プロフェッショナルなブランドイメージが必要となったとき、モネタイズの選択肢を広げたいときなど、あなたのブログが成長し、より高度な要件を必要とするようになったときに、WordPressへの移行を検討するタイミングかもしれません。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;無料ブログプラットフォームとWordPress、そのどちらが最適かはあなたのブログの目標とニーズによります。どちらのプラットフォームも一長一短があるため、あなたの状況に最も適した選択を行うことが重要です。&lt;/p&gt;&#10;&lt;p&gt;キーワード: ブログプラットフォーム, WordPress, 所有権, カスタマイズ, SEO, ブランドイメージ, モネタイズ, ブログ運営, ウェブサイト運営&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;前回「&lt;a class="link" href="https://ai.hack-le.com/wordpress/" &gt;WordPress入門: なぜ今すぐにでもWordPressを使い始めるべきなのか – 或る阿呆とAIと&lt;/a&gt;」あまりにもつまらない記事だったのだが、もう少し掘り下げたらもうちょっとマシになるんじゃないかと思えた。そこで、特に「所有権」というそれだけではよくわからないが、しかし重要な概念について掘り下げて聞いてみた。前よりはよくなったんじゃないかと思う。&lt;/p&gt;&#10;&lt;p&gt;以下のような質問をした。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;無料のブログサービスではなくWordPressを利用する理由として、「所有権」が主な理由になりうるのはなぜでしょうか。&lt;/li&gt;&#10;&lt;li&gt;無料のブログでも多くのテンプレートが用意されていたり、独自ドメインを利用したりするオプションがあるのではないでしょうか。&lt;/li&gt;&#10;&lt;li&gt;確かにプラットフォームの都合に振り回されるリスクは常に存在しますし、データの移行も難しいケースが多いようです。 そうすると、むしろWordPressを選ばない理由はなさそうですが、現実には有料のオプションを使ってもブログプラットフォームを利用するユーザーも多いようです。なぜでしょうか。&lt;/li&gt;&#10;&lt;li&gt;スモールスタートではブログプラットフォームも悪くない選択だということですね。 しかし、どこかでWordPressに移行を考えるようになる。それはどういうタイミングでしょうか。&lt;/li&gt;&#10;&lt;li&gt;所有権の有無によって、出来ることが大きく変わるわけですね。 では、ここまでの議論を長めの記事でまとめてください。 最初にタイトルをつけてください。 適切にH2の見出しをつけてください。 最後にキーワードを並べてください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;ただ1パラグラフあたりがあまりにも短い。読み応えがない。やはり出力の仕方はまだまだ工夫の余地がある。&lt;/p&gt;&#10;</description></item><item><title>WordPress入門: なぜ今すぐにでもWordPressを使い始めるべきなのか</title><link>https://ai.hack-le.com/wordpress/</link><pubDate>Mon, 26 Jun 2023 22:09:28 +0900</pubDate><guid>https://ai.hack-le.com/wordpress/</guid><description>&lt;h2 id="wordpressとは何か"&gt;WordPressとは何か&#10;&lt;/h2&gt;&lt;p&gt;WordPressは世界中のエンジニアから初心者まで、幅広いユーザーにとって便利で使いやすいツールとされています。このコンテンツ管理システム (CMS) はウェブサイトの構築・管理を容易にする一方で、多少の学習曲線があることも事実です。それでは、なぜWordPressがあなたのブログ作成のパートナーとして最適なのかを考えてみましょう。&lt;/p&gt;&#10;&lt;h2 id="初心者にとってのwordpress"&gt;初心者にとってのWordPress&#10;&lt;/h2&gt;&lt;p&gt;無料のブログプラットフォーム（例えばBloggerやTumblrなど）は非常に使いやすく、手軽にブログを開始できます。しかし、その簡単さと引き換えに、カスタマイズの自由度が限られる場合があります。&lt;/p&gt;&#10;&lt;p&gt;それに対してWordPressは、より高度なカスタマイズと機能性を提供しますが、その反面、初めての人にとっては少々学習が必要です。特に自分でホスティングを設定したり、テーマやプラグインをインストールしたりするといった工程が含まれます。&lt;/p&gt;&#10;&lt;h2 id="wordpressの利点と挑戦"&gt;WordPressの利点と挑戦&#10;&lt;/h2&gt;&lt;p&gt;WordPressの最大の利点はその柔軟性と拡張性です。あなたのニーズに合わせてカスタマイズが可能で、何千ものテーマやプラグインが利用可能です。さらに、SEO（検索エンジン最適化）に優れているため、ブログが検索エンジンに見つけやすくなります。&lt;/p&gt;&#10;&lt;p&gt;しかしその一方で、WordPressの学習曲線を乗り越えるためには、基本的な機能から学び始め、学ぶリソースを活用し、小さなステップで進めていくことが重要です。そして何よりも、試行錯誤を恐れず、コミュニティの力を借りて問題を解決することが大切です。&lt;/p&gt;&#10;&lt;h2 id="なぜあなたはwordpressを使うべきなのか"&gt;なぜあなたはWordPressを使うべきなのか&#10;&lt;/h2&gt;&lt;p&gt;WordPressを使うことで、ブログの完全なコントロールと所有権を保つことができます。これにより、あなたのサイトの見た目や機能性、モネタイゼーション、SEOなど、全てを自分で決定することができます。&lt;/p&gt;&#10;&lt;p&gt;また、大規模で活発なWordPressのコミュニティは、疑問や問題に対するサポートを提供します。そして、何よりもWordPressは成熟しており、世界中で広く使われているため、その開発と改善は継続的に行われています。&lt;/p&gt;&#10;&lt;p&gt;以上の理由から、WordPressはあなたがブログを開始するのに最適なプラットフォームであると言えます。最初は少し難しく感じるかもしれませんが、その可能性と柔軟性は、学習時間を投資する価値があります。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;WordPressを使用することで、あなた自身が自分のウェブサイトやブログを完全に制御し、カスタマイズする能力を持つことができます。最初は少し学習が必要かもしれませんが、その後の利益と成功はその労力に見合うものとなるでしょう。&lt;/p&gt;&#10;&lt;p&gt;キーワード: WordPress, ブログ, コンテンツ管理システム, CMS, 学習曲線, プラグイン, テーマ, SEO, コミュニティ, カスタマイズ, 柔軟性, 拡張性, モネタイゼーション, 所有権&lt;/p&gt;&#10;&lt;h2 id="質問と寸評"&gt;質問と寸評&#10;&lt;/h2&gt;&lt;p&gt;……という記事をChatGPT-4に書かせてみたわけだが、ちょっとこれを読んでWordPressを使おうという気になる人がいるかは甚だ疑問である。話が抽象的過ぎてなんとも言えない。ブログの完全なコントロールと所有権のところをもっと深掘りしたらよかったのだろうか？たとえばうざったい広告を置かなくて済むとか、プラットフォーマーから理不尽な規制をかけられないとか……。アク禁NGも自由にできるとか。&lt;/p&gt;&#10;&lt;p&gt;うーん、なるほど、そう考えると、やっぱり質問の仕方に問題があったかな。なお下記のような質問をChatGPT-4にした。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;WordPressはエンジニアにとっては便利で手軽なソフトだが、多くの人にとって難しいツールなのだろうか？&lt;/li&gt;&#10;&lt;li&gt;そのとおりだと思うが、ネットで実際にブログをやっている人たちの話を見ると、WordPressはどちらかというとチャレンジだと捉えられているように思える。恐らくはいわゆる無料ブログなんかと比べてだと思うが。自分でサイトを運用するということにハードルを感じる人は多いようだ。&lt;/li&gt;&#10;&lt;li&gt;ブログをやる限りは是非挑戦してほしいし、その価値があると思うが、難しさをかんじている人にはどう勧めたら良いだろうか。&lt;/li&gt;&#10;&lt;li&gt;使い始めた初心者にはそのアドバイスで良いと思うが、これから使うか悩んでいる人には、使うとこんないいことがあるよと、思ってもらえるようなことを言う必要があるだろう。&lt;/li&gt;&#10;&lt;li&gt;ここまでの話を長めの記事にまとめてください。&lt;/li&gt;&#10;&lt;li&gt;記事には、以下の条件を指定します。&lt;/li&gt;&#10;&lt;li&gt;最初にタイトルをつける&lt;/li&gt;&#10;&lt;li&gt;適度に見出しをつける&lt;/li&gt;&#10;&lt;li&gt;最後にキーワードを並べる&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;フォーマットだけは遵守しているね。&lt;/p&gt;&#10;</description></item><item><title>VPSからレンタルサーバーへ</title><link>https://ai.hack-le.com/vps/</link><pubDate>Mon, 26 Jun 2023 21:47:34 +0900</pubDate><guid>https://ai.hack-le.com/vps/</guid><description>&lt;h2 id="技術と便利さのバランス"&gt;技術と便利さのバランス&#10;&lt;/h2&gt;&lt;p&gt;私が長年愛用してきたVPS。最初はその自由度に惹かれ、WebサーバからSSHサーバ、メールサーバ、ファイルサーバまで、自分の手で一から構築してきました。SSL証明書の適用も、自分で行いました。それらは技術的に困難なタスクでしたが、それを乗り越えるたびに新たな学びがありました。&lt;/p&gt;&#10;&lt;p&gt;しかし、歳を重ねるとともに、VPSの自由度とカスタマイズ性がかえって負担に感じるようになりました。あらゆる運用がしんどく感じられるようになったのです。そこで、私はレンタルサーバーへと舞台を移しました。&lt;/p&gt;&#10;&lt;p&gt;初めは少し寂しく感じました。しかし、レンタルサーバーでの運用がとても快適だとすぐに気づきました。スクラップ&amp;amp;ビルドが簡単にできるようになったため、新しいウェブサイトを次々と立ち上げることができるようになりました。レンタルサーバーに移行してから、3つもの新しいサイトを短期間で立ち上げることができました。&lt;/p&gt;&#10;&lt;p&gt;特に感動的だったのは、ワンクリックでPHPのバージョンをアップデートできることです。これはVPSの時には考えられないことでした。技術的な問題ではなく、あくまで時間と手間の問題ですが、レンタルサーバーはこれらの手間を大幅に軽減してくれます。&lt;/p&gt;&#10;&lt;p&gt;しかし、ここで大事なのは、レンタルサーバーの便利さが「簡単」に感じられるのは、私がVPSで得た経験と知識があるからだということです。私が過去にVPSで構築した各種サーバーやSSL証明書の適用といった経験が、レンタルサーバーを使いこなすための土台となり、今の私を形成しています。&lt;/p&gt;&#10;&lt;p&gt;私の経験から言えることは、VPSもレンタルサーバーもそれぞれの目的とニーズに合わせた特性を持っているということです。何が必要か、何を優先すべきかは、それぞれのユーザーの視点で異なります。そして、どちらを選んだとしても、それは自分自身の知識と経験を増やし、成長するためのステップとなります。&lt;/p&gt;&#10;&lt;h2 id="質問と寸評"&gt;質問と寸評&#10;&lt;/h2&gt;&lt;p&gt;これはエッセイ風だが、ChatGPT-4に書かせたものだ。ただし、ベースは僕の経験談となっている。以下のようなことを質問（？）した。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;長年趣味でVPS上に個人ブログを構築していましたが、最近レンタルサーバーに切り替えました。VPSはWebサーバ以外にも色々なサーバを自由にたてられて、若かりし頃はとても勉強になりましたが、今となってはあらゆる運用がしんどくなってしまいました。レンタルサーバーでのブログ運用は、少し寂しいですが快適です。&lt;/li&gt;&#10;&lt;li&gt;レンタルサーバーに切り替えてから、WordPressのスクラップ&amp;amp;ビルドが簡単にできるようになった。つまり、簡単に新しいサイトを構築できるようになった。実際、僕はレンタルサーバーにしてから3つばかり新しいサイトを構築したが、これはVPSの時にはできなかっただろう。それは技術的な問題ではなく、手間の問題だった。 また、ワンクリックでPHPのバージョンをアップデートできたのはとても感動的なことだった。&lt;/li&gt;&#10;&lt;li&gt;この感動はVPSで苦労したから得られたものだと思う。 また、複数のサイトを簡単に構築できると感じられるのも、VPSで苦労したからだ。Webサーバだけではなく、SSHサーバ、メールサーバ、ファイルサーバ、色々構築してきた。SSL証明書も自分で適用した。その苦労があるからこそ簡単に思えるし、また、何をどう設定したらよいのかもわかる。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;僕の徒然とした書き込みを、うまいこと一つの文章に繋げていることがわかる。まぁ最後の最後に教訓めいたことを付け加えるのは、ChatGPTだからではあろう。&lt;/p&gt;&#10;</description></item></channel></rss>