シェルスクリプトマガジン

test

知っておきたいシェル関連技術(Vol.99掲載)

投稿日:2025.11.25 | カテゴリー: コード

著者:麻生 二郎

シェルは、LinuxやUNIX系OSを操作するためのプログラムです。本連載では、クラウドやリモートなど、近年のコンピュータ環境でのシェル活用のヒントになる情報を扱っていきます。第4回は、crondによる定期ジョブ実行を管理するオープンソースソフトウエア「Cronicle」を紹介します。 

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図4 /opt/cronicle/conf/config.jsonファイルの変更箇所

■STARTTLSの場合

"email_from": "Cronicle Admin <shell@example.com>",
"smtp_hostname": "smtp.example.com",
"mail_options":{
    "port":587,
    "secure": false,
    "auth":{
        "user":"shell@example.com",
        "pass":"password"
    }
},

■SMTPSの場合

"email_from": "Cronicle Admin <shell@example.com>",
"smtp_hostname": "smtp.example.com",
"mail_options":{
    "port":465,
    "secure": true,
    "auth":{
        "user":"shell@example.com",
        "pass":"password"
    }
},

作りながら学ぶVue.js入門(Vol.99掲載)

投稿日:2025.11.25 | カテゴリー: コード

著者:大津 真

JavaScriptフレームワークの中でも、学びやすさと柔軟さで人気を集めている「Vue.js」。本連載では、Vue.jsの基礎から実践的な使い方までを、分かりやすく丁寧に解説していきます。一緒にフロントエンド開発の楽しさを体験してみましょう。第4回では、v-onディレクティブの活用と、VueアプリケーションからDOM(Document Object Model)を操作する方法について説明します。

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図1 「event-props/src/App.vue」ファイルのコード

<script setup>
import { ref } from 'vue'

function eventTest(e) {
  console.log(e)
}
</script>

<template>
  <button @click="eventTest">Click me</button>
</template>

図1 「event-props/src/App.vue」ファイルのコード

<script setup>
import { ref } from 'vue'
const event = ref(null)

function eventTest(e) {
  event.value = e
}
</script>

<template>
  <div id="back" @click="eventTest" @dblclick="eventTest">
    <h1>Event Test</h1>
    <div id="box" @mouseover="eventTest" @mouseout="eventTest">
      <p>My Box</p>
    </div>
    <p>Event type: {{ event?.type }}</p>
    <p>x:{{ event?.clientX }} y: {{ event?.clientY }}</p>
  </div>
</template>

<style scoped>
#back {
  width: 100vw;
  height: 100vh;
}
#box {
  width: 100px;
  height: 100px;
  background-color: #f00;
  margin: 0 auto;
}
</style>

図6 「src/style.css」ファイルの変更例

(略)
#app {
  max-width: 1280px;
  margin: 0 auto;
  /* padding: 2rem; */  ←コメントにする
  text-align: center;
}
(略)

図7 useTemplateRef関数でDOM要素を取得するコードの例

<template>
(略)
  <img ref="fish" id="fish" src="./assets/fish1.jpg" />
(略)
</template>
<script setup>
(略)
  const fish = useTemplateRef("fish");
(略)
</script>

図8 「event-test2/src/App.vue」ファイルのコード

<!-- App.vue -->
<template>
  <div id="back" @click="moveImg">
    <img ref="fish" id="fish" src="./assets/fish1.jpg" />
  </div>
</template>

<script setup>
import { useTemplateRef, onMounted } from 'vue'
// テンプレート参照を取得
const fish_ref = useTemplateRef("fish")

function moveImg(e) {
  // transitionの設定
  const duration = "1s" // 移動時間
  fish_ref.value.style.transition = \
    left ${duration} ease, top ${duration} ease, \
    transform 0.3s ease

  // クリック位置に移動
  const x = e.clientX  - fish_ref.value.width / 2
  const y = e.clientY  - fish_ref.value.height / 2
  fish_ref.value.style.left = ${x}px
  fish_ref.value.style.top  = ${y}px

  // クリック方向に応じて向きを変える
  if (e.clientX < fish_ref.value.offsetLeft) {
    fish_ref.value.style.transform = 'scaleX(-1)' // 左向き
  } else {
    fish_ref.value.style.transform = 'scaleX(1)'  // 右向き
  }
}
</script>
<style scoped>
#back {
  position: fixed;
  inset: 0;
}
#fish {
  position: absolute;
  width: 100px;
  left:  100px; /* 初期位置 X */
  top:   100px; /* 初期位置 Y */
}
</style>

図10 HTMLテンプレート部分の変更箇所

(略)
<div id="back" @click="moveImg(false, $event)"
               @contextmenu="moveImg(true, $event)">
  <img ref="fish" id="fish" src="./assets/fish1.jpg" />
</div>
(略)

図11 JavaScript部分の変更箇所(抜粋)

(略)
function moveImg(isFast, e) {
  e.preventDefault(); // 右クリックメニューを防ぐ
(略)
  const duration = isFast ? "0.3s" : "0.8s";
  el.style.transition = left ${duration} ease, \
                        top ${duration} ease, \
                        transform 0.3s ease;
(略)

図12 不適切なコードの例

(略)
<script setup>
import { useTemplateRef, onMounted } from 'vue';

const fish = useTemplateRef("fish");

const el = fish.value
el.style.left = '100px'  // 左端の座標を設定
el.style.top  = '100px'  // 上端の座標を設定
(略)

図13 書き換えた部分のコード

onMounted(() => {
  const el = fish.value;
  if (el) {
    // 親要素の位置とサイズを取得
    const parentRect = el.offsetParent.getBoundingClientRect();
    // 初期位置を画面中央に設定
    const x = parentRect.width / 2 - el.width / 2;
    const y = parentRect.height / 2 - el.height / 2;
    el.style.left = ${x}px;
    el.style.top = ${y}px;
  }
});

※「&lt; 」を「<」に置き換えてください。

Pythonあれこれ(Vol.99掲載)

投稿日:2025.11.25 | カテゴリー: コード

著者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第29回では、物体の動きや力の作用など、現実世界の物理法則を数値的に計算してシミュレーションする「物理演算」にチャレンジします。

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図6 playground.pyファイルの最後の部分にあるコード

def main():
    demo = PhysicsDemo()
    demo.run()

if __name__ == "__main__":
    doprof = 0
    if not doprof:
        main()
    else:
        import cProfile
        import pstats

        prof = cProfile.run("main()", "profile.prof")
        stats = pstats.Stats("profile.prof")
        stats.strip_dirs()
        stats.sort_stats("cumulative", "time", "calls")
        stats.print_stats(30)

図7 PhysicsDemoクラスのrun()メソッドのコード

def run(self):
    while self.running:
        self.loop()

図8 PhysicsDemoクラスのloop()メソッドのコード

def loop(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            self.running = False
(略)
            self.space.gravity = g.rotated_degrees(45)

    mpos = pygame.mouse.get_pos()
    if pygame.key.get_mods() & \
          pygame.KMOD_SHIFT and pygame.mouse.get_pressed()[2]:
        p = self.flipyv(Vec2d(*mpos))
        self.poly_points.append(p)
    hit = self.space.point_query_nearest(
        self.flipyv(Vec2d(*mpos)), 0, pm.ShapeFilter()
    )
    if hit != None:
        self.shape_to_remove = hit.shape
    else:
        self.shape_to_remove = None

    ### Update physics
    if self.run_physics:
        x = 1
        dt = 1.0 / 60.0 / x
        for x in range(x):
            self.space.step(dt)
            for ball in self.balls:
                # ball.body.reset_forces()
                pass
            for poly in self.polys:
                # poly.body.reset_forces()
                pass

    ### Draw stuff
    self.draw()

    ### Check for objects outside of the screen,
    #   we can remove those Balls
    xs = []
    for ball in self.balls:
        if (
            ball.body.position.x < -1000
            or ball.body.position.x > 1000
            or ball.body.position.y < -1000
            or ball.body.position.y > 1000
        ):
            xs.append(ball)
    for ball in xs:
        self.space.remove(ball, ball.body)
        self.balls.remove(ball)

    # Polys
(略)

    ### Tick clock and update fps in title
    self.clock.tick(50)
    pygame.display.set_caption("fps: " + str(self.clock.get_fps()))

図9 create_ball()メソッドのコード

def create_ball(self, point, mass=1.0, radius=15.0):

    moment = pm.moment_for_circle(mass, 0.0, radius)
    ball_body = pm.Body(mass, moment)
    ball_body.position = Vec2d(*point)

    ball_shape = pm.Circle(ball_body, radius)
    ball_shape.friction = 1.5
    ball_shape.collision_type = COLLTYPE_DEFAULT
    self.space.add(ball_body, ball_shape)
    return ball_shape

図10 PhysicsDemoクラスのコンストラクタのコード

def __init__(self):
    self.running = True
    ### Init pygame and create screen
    pygame.init()
    self.w, self.h = 600, 600
    self.screen = pygame.display.set_mode((self.w, self.h))
    self.clock = pygame.time.Clock()

    ### Init pymunk and create space
    self.space = pm.Space()
    self.space.gravity = (0.0, -900.0)

    ### Walls
    self.walls = []
    self.create_wall_segments([(100, 50), (500, 50)])

    ## Balls
    # balls = [createBall(space, (100,300))]
    self.balls = []

    ### Polys
    self.polys = []
    h = 10
    for y in range(1, h):
        # for x in range(1, y):
        x = 0
        s = 10
        p = Vec2d(300, 40) + Vec2d(0, y * s * 2)
        self.polys.append(self.create_box(p, size=s, mass=1))
 
    self.run_physics = True

    ### Wall under construction
    self.wall_points = []
    ### Poly under construction
    self.poly_points = []

    self.shape_to_remove = None
    self.mouse_contact = None

図11 playground.pyファイルの変更差分

133a134,135
>         pygame.draw.circle(self.screen, 
>             pygame.Color("skyblue"), p, int(r), 0)
140c142
<         pygame.draw.lines(self.screen, pygame.Color("lightgray"), False, [pv1, pv2])
---
>         pygame.draw.lines(self.screen, pygame.Color("gray"), False, [pv1, pv2], 3)
148c150,151
<             color = pygame.Color("green")
---
>             color = pygame.Color("forestgreen")
>             color2 = pygame.Color("lightgreen")
151c154,156
<         pygame.draw.lines(self.screen, color, False, ps)
---
>             color2 = pygame.Color("orange")
>         pygame.draw.polygon(self.screen, color2, ps, 0)
>         pygame.draw.polygon(self.screen, color, ps, 2)

※「&#91;」を「[」に、「&lt; 」を「<」に置き換えてください。

Markdownを活用する(Vol.99掲載)

投稿日:2025.11.25 | カテゴリー: コード

筆者:藤原 由来

本連載では文書の装飾・構造付けを手軽に行える記法であるMarkdownを用いて、さまざまな文書や成果物を作成する方法を紹介します。前回に引き続き、文書変換ツール「Pandoc」の文書作成方法を紹介します。今回はPandocのフィルタ機能により柔軟な文書変換を実施する方法を解説します。

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図4 入力とするMarkdownテキストファイル(sample-input.md)

# カレーの作り方

おいしいカレーを作りましょう。

## 材料

- 牛肉
- 玉ねぎ
- にんじん
- カレールー
- 水

図5 フィルタ適用後に出力されるMarkdownテキストファイル(sample-output.md)

# カレーの作り方

おいしいカレーを作りましょう。

## ★材料

- 牛肉
- 玉ねぎ
- にんじん
- カレールー
- 水

図7 Pythonで記述したJSONフィルタ

#!/usr/bin/env -S uv run --script
import panflute as pf

def add_star_to_header2(elem, doc):
    """
    レベル2の見出しに星印「★」を追加するフィルタ関数
    """
    # 要素の種類がHeaderで、レベルが2の場合
    if isinstance(elem, pf.Header) and elem.level == 2:
        # 星印を表す要素を生成
        star = pf.Str("★")

        # 見出しの内容の先頭に星印を追加
        elem.content.insert(0, star)
    return elem

def main(doc=None):
    """
    メイン関数: フィルタを実行
    """
    return pf.run_filter(add_star_to_header2, doc=doc)

# スクリプトが直接実行された場合にmain()を呼び出す
if __name__ == "__main__":
    main()

図9 Luaフィルタの内容(add_star.lua)

function Pandoc(doc)
  -- 各ブロックについて処理
  for i, elem in ipairs(doc.blocks) do
    -- 要素の書類がHeaderで、レベルが2の場合
    if elem.t == "Header" and elem.level == 2 then
      -- 内容の先頭に星印「★」を追加
      table.insert(elem.content, 1, pandoc.Str("★"))
    end
  end
  return doc
end

図10 別の記述を用いたLuaフィルタの内容(add_star2.lua)

function Header(elem)
  -- 見出しのレベルが2の場合
  if elem.level == 2 then
    -- 内容の先頭に星印「★」を追加
    table.insert(elem.content, 1, pandoc.Str("★"))
  end
  return elem
end

図A-2 図表の定義と、図表の参照を組み合わせた例

[@fig:sample]は、サンプル図を示しています。
[@tbl:sample]は、サンプル表を示しています。

![サンプル図](cat1.png){#fig:sample}

| ヘッダー1 | ヘッダー2 |
|-----------|-----------|
| データ1   | データ2   |

: サンプル表 {#tbl:sample} 

Generative AIコンパス(Vol.99掲載)

投稿日:2025.11.25 | カテゴリー: コード

筆者:為藤 アキラ

AI技術の進化は、社会や産業のあり方を大きく変えつつあります。本連載では、国内外の最新動向や実践的な技術トピックを、日本の現場視点も交えながら分かりやすく解説します。執筆は、産学連携で生成AI活用を推進するGenerative AI Japan(略称:GenAI)のメンバーが担当します。第1回では、人間がAIの処理に積極的に関与する仕組みである「HITL(Human In The Loop)」のパターンについて解説します。

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図2 標準化したプロンプトのひな型の例

【入力】
目的/想定読者/素材/制約(文字数・禁止表現)/評価観点
【AI出力構成】
1. 本文案(Markdown形式・見出し3階層まで)
2. 自己検証結果
   - 不確実な主張に★マーク
   - 各主張の根拠URL(最大3件)
   - リスク箇所の指摘
3. 人間レビュー推奨箇所(優先度順3件)

図4 判定結果に関する情報の、人向けの要約を生成するプロンプトの例

① 判定:自動可 / 要承認 / 却下
② 理由(3点)
③ 不足情報(Required)
④ 実行提案(短文)
⑤ ロールバック(失敗時の戻し方)
⑥ 監査メモ:承認者/日時/版数

図5 判定結果に関する、システム連携や監査用の情報を生成するプロンプトの例

【役割】承認ゲート:入力を要約し、実行可否と根拠を機械可読で返す
【返却JSON】
{
  "auto_action": "needs_approval",
  "confidence": 0.85,
  "risk_score": 35,
  "reasons": ["金額が社内閾値を超過", "在庫残が3日分で変動大", "取引先情報が更新待ち"],
  "required_context": ["最新在庫CSV", "購買稟議URL"],
  "proposed_action": "在庫再評価後に数量50%で発注",
  "human_checklist": ["金額閾値を満たすか", "在庫の確度", "契約条件の例外有無", "広報リスク", "ロールバック可否"],
  "logs": "s3://audit/workflows/po-2025-10/ 24ヶ月保持",
  "rollback": "API: /orders/cancel を実行し在庫を戻す。再開条件:在庫確度80%以上"
}
【判定基準】
- confidence ? 0.90 かつ risk_score ? 20 → approve
- 0.70 ? confidence < 0.90 または 20 < risk_score ? 60 → needs_approval
- それ以外 → reject

特集1 特集1 Playwright MCPによるWebシステム自動E2Eテスト(Vol.99記載)

投稿日:2025.11.25 | カテゴリー: コード

著者:藤原 由来

Webシステムに対するE2E(End-to-End)テストの実施は、手間と労力のかかる作業です。しかし、生成AIを活用した「Playwright MCP」を使えば、誰でも簡単にE2Eテストの作成・自動実行が可能です。本特集では、Playwright MCPの基本的な使い方を紹介し、実際に日本語による指示だけでE2Eテストを作成・自動実行する方法を解説します。

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図30 テストシナリオとなるプロンプト

@playwright-mcp Webブラウザを起動して、以下のWebアプリに対して、E2Eテストを実行してください。

## URL

http://localhost:3000/

## テストケース

- ログイン機能
  - ユーザー名 test / パスワード mypassword でログインできること
  - ユーザー名 test / パスワード bar の場合はエラーメッセージを出力すること
  - ユーザー名 foo  / パスワード mypassword の場合はエラーメッセージを出力すること
- ログアウト機能
  - ユーザー名 test / パスワード mypassword でログインし、ログアウトするとログイン画面に遷移すること
- TODO機能
  - タスクを作成できること
  - 作成済みのタスクを編集できること
  - タスクにチェックを入れると、完了済みの状態になること
  - 完了済みタスクを未完了に戻せること
  - タスクを削除できること

※「&#47;&#47;」を「//」に置き換えてください。

シェルスクリプトマガジンvol.99 Web掲載記事まとめ

投稿日:2025.11.25 | カテゴリー: コード

004 レポート 制作ソフト「Affinity」が無償化
005 レポート さくらのAI Engine一般提供開始
006 製品レビュー ポータブルSSD「SSD-SDHU3シリーズ」
007 NEWS FLASH
008 特集1 Playwright MCPによるWebシステム自動E2Eテスト/藤原由来 コード掲載
018 特別企画 Boxのワークフロー自動化とAIで業務効率化/藤井健志、葵健晴、武田新之助
026 ARM/RISC-V搭載コンピュータボード/米田聡
031 インタビュー パロアルトネットワークス Hiroshi Alley氏
032 Generative AIコンパス/為藤アキラ コード掲載
036 Markdownを活用する/藤原由来 コード掲載
046 Pythonあれこれ/飯尾淳 コード掲載
052 作りながら学ぶVue.js入門/大津真 コード掲載
060 知っておきたいシェル関連技術/麻生二郎 コード掲載
066 Techパズル
067 コラム「社内のERPプロジェクト」/シェル魔人

Vol.99

投稿日:2025.11.25 | カテゴリー: バックナンバー

 システム開発におけるテスト工程の中でも、最も手間と工数がかかるのがユーザーインタフェース(UI)のテストです。もし、言葉による指示だけでUIテストを作成し、自動実行できたらとても便利です。近年のAI(人工知能)の進化により、こうしたことが現実のものとなりつつあります。
 特集1では、AIを活用してUIテスト(End-to-Endテスト)を自動化できる「Playwright MCP」について、実例を交えながら解説します。
 特別企画では、クラウドストレージサービス「Box」が備えるワークフロー自動化とAI機能を紹介します。Boxは、単なるファイル保存の場にとどまらず、保存された文書を利用した承認フローなどの作成や自動実行を、自身の機能だけで実現できます。また、AI機能は、セキュリティを担保しながら、保存文書の検索、要約、抽出などを可能にし、ビジネスでの活用を支援します。
 このほか、二つの新連載が始まりました。国内外のAIに関する最新トレンドを分かりやすく紹介する「Generative AIコンパス」と、LinuxとRTOSが動作する小型コンピュータボード「Milk-V Duo 256M」と、電子工作を扱う「ARM/RISC-V搭載コンピュータボード」です。
 今回も読み応え十分のシェルスクリプトマガジン Vol.99。ぜひお見逃しなく!

※記事掲載のコードはこちら。記事の補足情報はこちら

※読者アンケートはこちら

Vol.99 補足情報

投稿日:2025.11.18 | カテゴリー: コード

連載 作りながら学ぶVue.js入門

記事で紹介したサンプルコードの完全版と、その実行方法を記したMarkdown文書をまとめたZIPファイルは、ここからダウンロードできます。

情報は随時更新致します。

  • shell-mag ブログの 2025年11月 のアーカイブを表示しています。

  • -->