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

test

これだけは覚えておきたいLinuxコマンド(Vol.91掲載)

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

著者:大津 真

本連載では、Linuxの初心者に覚えておいてほしいコマンドを紹介していきます。ここで紹介するコマンドさえ押さえておけば、基本的な操作に困ることはなくなるでしょう。第2回では、主にテキストファイルを処理するための基本コマンドについて解説します。

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

図6 「members.csv」ファイルの内容

001,大津一郎,男,43,東京
002,江南直子,女,8,埼玉
003,唐木田信ー,男,43,福岡
004,森岡一郎,男,41,東京
005,秋山敬一郎,男,44,秋田
006,山田謙一,男,9,福岡
007,山田一郎,男,45,東京
009,福岡花子,女,35,東京
010,白戸二郎,男,39,北海道

中小企業手作りIT化奮戦記(Vol.91掲載)

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

著者:佐藤 楓真

今回は、「焼きなまし法」と呼ばれる手法で、すべての都市を1回訪問して出発地点に帰るまでの最短経路を求める「巡回セールスマン問題」を近似的に解いてみます。焼きなまし法のベースとなる「山登り法」についても解説します。使用するプログラミング言語は、C++です。

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

図3 図1の巡回セールスマン問題を山登り法で解くC++プログラムの例

#include <iostream>
#include <algorithm>
using namespace std;
#define TL 3  //制限時間
#define N 4

int d[N][N] = {{0, 2, 10, 5},
               {2, 0, 5, 3},
               {10, 5, 0, 4},
               {5, 3, 4, 0}};
int ans[N+1] = {0, 1, 3, 2, 0};
int rand_num(void) {
  return rand() % N + 1;
}
int calc_dist(void) {
  int sum = 0;
  for (int i = 0; i < N; i++) {
      sum += d[ans[i]][ans[i+1]];
  }
  return sum;
}
int main(void) {
  srand((unsigned)time(NULL));
  int st_time = clock();
  while ((clock() - st_time) / CLOCKS_PER_SEC < TL) {
    int L = rand_num(), R = rand_num();
    if (L > R) swap(L, R);
    int bf_dist = calc_dist();
    reverse(ans + L, ans + R);
    int af_dist = calc_dist();
    if (bf_dist < af_dist) reverse(ans + L, ans + R);
  }
  for (int i = 0; i < N+1; i++) {
    cout << ans[i] + 1 << " ";
  }
  cout << endl << calc_dist() << endl;
  return 0;
}

図4 都市数「5000」のテスト用データを作成するC++プログラム

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
#define N 5000

int main(void) {
  srand((unsigned)time(NULL));
  for (int num = 1; num <= 100; num++) {
    vector<vector<int>> d(N, vector<int>(N));
    for (int i = 0; i < N; i++) {
      for (int j = i; j < N; j++) {
        if (i == j) {
          d[i][j] = 0;
        } else {
          d[i][j] = rand() % 5000 + 1;
        }
      }
    }
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < i; j++) {
        d[i][j] = d[j][i];
      }
    }
    string name = "case" + to_string(num) + ".txt";
    ofstream out(name);
    out << N << endl;
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < N; j++) {
        out << d[i][j] << " ";
      }
        out << endl;
    }
  }
  return 0;
}

図5 テスト用データに基づく巡回セールスマン問題を山登り法で解くC++プログラムの例

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
#define TL 3  //制限時間

int calc_dist(vector<vector<int>>& dist, vector<int>& ans, int N) {
  int sum = 0;
  for (int i = 0; i < N; i++) {
    sum += dist[ans[i]][ans[i+1]];
  }
  return sum;
}
int rand_num(int N){
  return rand() % N + 1;
}
int main(void) {
  long long ave = 0;
  for (int num = 1; num <= 100; num++) {
    srand((unsigned)time(NULL));
    string name = "case" + to_string(num) + ".txt";
    ifstream infile(name);
    int N;
    infile >> N;
    vector<vector<int>> d(N, vector<int>(N));
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < N; j++) {
        infile >> d[i][j];
      }
    }
    vector<int> ans(N + 1);
    for (int i = 0; i < N; i++) ans[i] = i;
    ans[N] = 0;
    int st_time = clock();
    while ((clock() - st_time) / CLOCKS_PER_SEC < TL) {
      int bf_dist = calc_dist(d, ans, N);
      int L = rand_num(N), R = rand_num(N);
      if (L > R) swap(L, R);
      reverse(ans.begin() + L, ans.begin() + R);
      int af_dist = calc_dist(d, ans, N);
      if (af_dist > bf_dist) reverse(ans.begin() + L, ans.begin() + R);
    }
    ave += calc_dist(d, ans, N);
  }
  cout << ave / 100.0 << endl;
  return 0;
}

図7 テスト用データに基づく巡回セールスマン問題を焼きなまし法で解くC++プログラムの例

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <fstream>
#include <cmath>
using namespace std;
#define MAX_TMP 100.0  //初期温度
#define TL 3  //制限時間

int calc_dist(vector<vector<int>>& dist, vector<int>& ans, int N) {
  int sum = 0;
  for (int i = 0; i < N; i++) {
    sum += dist[ans[i]][ans[i+1]];
  }
  return sum;
}
int rand_num(int N) {
  return rand() % N + 1;
}
double rand_p(void) {
  return (double)rand() / RAND_MAX;
}
int main(void) {
  srand((unsigned)time(NULL));
  long long ave = 0;
  for (int num = 1; num <= 100; num++) {
    string name = "case" + to_string(num) + ".txt";
    ifstream infile(name);
    int N;
    infile >> N;
    vector<vector<int>> d(N, vector<int>(N));
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < N; j++) {
        infile >> d[i][j];
      }
    }
    vector<int> ans(N + 1);
    for (int i = 0; i < N; i++) ans[i] = i;
    ans[N] = 0;
    int st_time = clock();  //焼きなまし開始時間
    while ((clock() - st_time) / CLOCKS_PER_SEC < TL ) {
      int bf_dist = calc_dist(d, ans, N);
      int L = rand_num(N), R = rand_num(N);
      if (L > R) swap(L, R);
      reverse(ans.begin() + L, ans.begin() + R);
      int af_dist = calc_dist(d, ans, N);
      double t = (double)(clock() - st_time) / CLOCKS_PER_SEC;  //経過時間
      double tmp = MAX_TMP - MAX_TMP * (t / TL);  //現在の温度
      double p = exp((bf_dist - af_dist) / tmp);  //採用確率
      if (rand_p() > p) reverse(ans.begin() + L, ans.begin() + R);
    }
    ave += calc_dist(d, ans, N);
  }
  cout << ave / 100.0 <<endl;
  return 0;
}

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

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

著者:藤原 由来

本連載では文書の装飾・構造付けを手軽に行える記法であるMarkdownを用いて、さまざまな文書や成果物を作成する方法を紹介します。今回は、Markdownを用いて書籍を制作できる組版アプリ「Vivliostyle」の導入と、書籍作成の基本について説明します。

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

図11 chap1.mdファイルの内容

# 後注と脚注の例

これは後注[^1]の例です。
インラインで後注^[これも章の後ろに表示される]もできます。

[^1]: 各章の後部にまとめて出力されるタイプの注釈

こちらは脚注<span class="footnote">ページ直下に表示される</span>です。

図12 chap2.mdファイルの内容

# {吾輩|わがはい}は猫である。

{吾輩|わがはい}は猫である。名前はまだ無い。

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

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

著者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第21回では、「ハノイの塔」の解法「GDHP(Gniibe Distributed Hanoi Protocol)」の手順をアニメーションで表示するPythonアプリを作成します。

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

図2 GDHPの手順をアニメーションで表示するJavaScriptコード

const COLORS = [ 'crimson', 'forestgreen', 'yellow', 'royalblue',
                 'saddlebrown', 'hotpink', 'darkorange', 'darkmagenta' ];
const NUM_OF_DISKS = COLORS.length;
const BASE_LENGTH = 200;
const C_WIDTH  = 3.732 * BASE_LENGTH;
const C_HEIGHT = 3.500 * BASE_LENGTH;
const DISK_R = 0.9 * BASE_LENGTH;
const POLE_R = 15;
const POSITIONS = { 'Source'      : [0.268, 0.714],
                    'Auxiliary'   : [0.500, 0.286],
                    'Destination' : [0.732, 0.714] };
const FLASHING_COUNTER = 20;
const STEPS = 30;

class Vector {
  constructor(x,y) {
    this.x = x;
    this.y = y;
  }
}
class Position extends Vector {
  constructor(x,y) { super(x,y); }
  move(vec) {
    this.x += vec.x;
    this.y += vec.y;
  }
}
class Disk {
  constructor(level) {
    this.level = level;
    this.color = COLORS[level];
    this.r = (DISK_R-POLE_R)*(NUM_OF_DISKS-level)/NUM_OF_DISKS + POLE_R;
  }
}
class MovingDisk extends Disk {
  constructor(level,from,to) {
    super(level); 
    [sx,sy] = [from.pos.x,from.pos.y];
    [dx,dy] = [to.pos.x,  to.pos.y];
    this.pos = new Position(sx,sy);
    this.mvec = new Vector((dx-sx)/STEPS,(dy-sy)/STEPS);
    this.move_ctr = 0;
    this.from = from;
    this.to = to;
  }
  step_forward() {
    this.pos.move(this.mvec);
    this.move_ctr++;
  }
  finish_p() {
    var ret_flag = false;
    if (ret_flag = (this.move_ctr == STEPS)) {
      this.to.disks.push(new Disk(this.level));
    }
    return ret_flag;
  }
}
class Tower {
  constructor(name, disks, direction=null) {
    this.name = name;
    this.disks = [];
    for (var i = 0; i < disks; i++) {
      this.disks.push(new Disk(i));
    }
    this.direction = direction;
    this.moving = false;
    this.flash_ctr = 0;
  }
  get toplevel() {
    var l = this.disks.length;
    // '-1' means there is no disk.
    return (l > 0) ? this.disks[l-1].level : -1;
  }
}
var src = new Tower('Source', NUM_OF_DISKS);
var aux = new Tower('Auxiliary',   0, src);
var dst = new Tower('Destination', 0, src);
// In the case of NUM_OF_DISKS is odd, 
// the src must face the src.
// Otherwise, the src faces the aux.
src.direction = (COLORS.length % 2 == 1) ? dst : aux;
// the reference to moving disk is stored to this variable.
var moving_disk = null;

function setup() {
  createCanvas(C_WIDTH, C_HEIGHT);
  frameRate(30);
  [src,aux,dst].forEach(function(t) {
    [rx,ry] = POSITIONS[t.name];
    t.pos = new Position(rx * C_WIDTH, ry * C_HEIGHT);
  })
}
function base_drawing() {
  background('beige');
  [src,aux,dst].forEach(function(t) {
    // draw disks
    t.disks.forEach(function(d) {
      stroke('black');
      fill(d.color);
      ellipse(t.pos.x,t.pos.y,2*d.r);
    })
    // draw a pole
    stroke('brown');
    fill(t.moving & (t.flash_ctr < FLASHING_COUNTER/2) ? 'gold' : 'white');
    ellipse(t.pos.x,t.pos.y,2*POLE_R);
    // draw a direction
    stroke('navy');
    [sx, sy] = [t.pos.x, t.pos.y];
    [dx, dy] = [t.direction.pos.x, t.direction.pos.y];
    r = POLE_R / Math.sqrt((dx-sx)*(dx-sx)+(dy-sy)*(dy-sy));
    [dx, dy] = [(dx-sx)*r+sx, (dy-sy)*r+sy];
    line(sx,sy,dx,dy);
  })
}
function flash_poles() {
  [src,aux,dst].forEach(function(t) {
    t.moving = (t.direction.direction === t);
    t.flash_ctr += 1;
    t.flash_ctr %= FLASHING_COUNTER;
  })
}
function pop_disk(src,aux,dst) {
  var towers = [src,aux,dst].filter(t => t.moving);
  var idx,from,to;
  idx = (towers[0].toplevel > towers[1].toplevel) ? 0 : 1;
  [from, to] = [towers[idx], towers[1-idx]];
  return new MovingDisk(from.disks.pop().level,from,to);
}
function draw_moving_disk() {
  var d = moving_disk;
  d.step_forward();
  stroke('black');
  fill(d.color);
  ellipse(d.pos.x,d.pos.y,2*d.r);
  return d.finish_p();
}
function turn() {
  [moving_disk.from,moving_disk.to].forEach(function(t) {
    t.direction = ([src,aux,dst]
      .filter(x => (x !== t) && (x !== t.direction)))[0];
    t.moving = false;
  })
}
function draw() {
  // base drawing
  base_drawing();
  // find two exchange-towers out of three
  flash_poles();
  // start moving
  if (moving_disk == null) {
    moving_disk = pop_disk(src,aux,dst);
  } else {
    if (draw_moving_disk()) {
      turn();
      moving_disk = null;
    }
  }
}

図3 Pygameを用いて描画ウィンドウを表示するPythonコード

import pygame

pygame.init()
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption('Pygame Window')

while True:
  for event in pygame.event.get():
    if event.type == pygame.TEXTINPUT and event.text == 'q':
      pygame.quit()
      exit()

  screen.fill('lavender')

  pygame.display.flip()
  pygame.time.delay(30)

図5 GDHPの手順をアニメーションで表示するPythonコード

import pygame
import math

COLORS = [ 'crimson', 'forestgreen', 'yellow', 'royalblue',
           'saddlebrown', 'hotpink', 'darkorange', 'darkmagenta' ]
NUM_OF_DISKS = len(COLORS)
BASE_LENGTH = 200
C_WIDTH  = 3.732 * BASE_LENGTH
C_HEIGHT = 3.500 * BASE_LENGTH
DISK_R = 0.9 * BASE_LENGTH
POLE_R = 15
POSITIONS = { 'Source'      : [0.268, 0.714],
              'Auxiliary'   : [0.500, 0.286],
              'Destination' : [0.732, 0.714] }
FLASHING_COUNTER = 20
STEPS = 30

class Vector:
  def __init__(self, x, y):
    self.x = x
    self.y = y
class Position(Vector):
  def __init__(self, x, y):
    super().__init__(x, y)
  def move(self, vec):
    self.x += vec.x
    self.y += vec.y
class Disk:
  def __init__(self, level):
    self.level = level
    self.color = COLORS[level]
    self.r = (DISK_R-POLE_R)*(NUM_OF_DISKS-level)/NUM_OF_DISKS + POLE_R
class MovingDisk(Disk):
  def __init__(self, level, frm, to):
    super().__init__(level) 
    [sx, sy] = [frm.pos.x, frm.pos.y]
    [dx, dy] = [to.pos.x,  to.pos.y]
    self.pos = Position(sx,sy)
    self.mvec = Vector((dx-sx)/STEPS,(dy-sy)/STEPS)
    self.move_ctr = 0
    self.frm = frm
    self.to = to
  def step_forward(self):
    self.pos.move(self.mvec)
    self.move_ctr += 1
  def finish_p(self):
    ret_flag = (self.move_ctr == STEPS)
    if ret_flag:
      self.to.disks.append(Disk(self.level))
    return ret_flag
class Tower:
  def __init__(self, name, disks, direction=None):
    self.name = name
    self.disks = []
    for i in range(disks):
      self.disks.append(Disk(i))
    self.direction = direction
    self.moving = False
    self.flash_ctr = 0
  def toplevel(self):
    l = len(self.disks)
    # '-1' means there is no disk.
    return self.disks[l-1].level if l > 0 else -1
def setup():
  pygame.init()
  screen = pygame.display.set_mode((C_WIDTH, C_HEIGHT))
  pygame.display.set_caption('GDHP')
  for t in [src,aux,dst]:
    [rx, ry] = POSITIONS[t.name]
    t.pos = Position(rx * C_WIDTH, ry * C_HEIGHT)
  return screen
def base_drawing():
  screen.fill('beige')
  for t in [src,aux,dst]:
    # draw disks
    for d in t.disks:
      pygame.draw.circle(screen, d.color, (t.pos.x,t.pos.y), d.r)
      pygame.draw.circle(screen, 'black', (t.pos.x,t.pos.y), d.r, 1)
    # draw a pole
    fillcolor = 'gold' \
      if t.moving and t.flash_ctr < FLASHING_COUNTER/2 else 'white' 
    pygame.draw.circle(screen, fillcolor, (t.pos.x,t.pos.y), POLE_R)
    pygame.draw.circle(screen, 'brown', (t.pos.x,t.pos.y), POLE_R, 1)
    # draw a direction
    [sx, sy] = [t.pos.x, t.pos.y]
    [dx, dy] = [t.direction.pos.x, t.direction.pos.y]
    r = POLE_R / math.sqrt((dx-sx)*(dx-sx)+(dy-sy)*(dy-sy))
    [dx, dy] = [(dx-sx)*r+sx, (dy-sy)*r+sy]
    pygame.draw.line(screen, (0,0,128), (sx,sy), (dx,dy), 3)
def flash_poles():
  for t in [src,aux,dst]:
    t.moving = (t.direction.direction == t)
    t.flash_ctr += 1
    t.flash_ctr %= FLASHING_COUNTER
def pop_disk(src,aux,dst):
  towers = list(filter(lambda x: x.moving, [src,aux,dst]))
  idx = 0 if towers[0].toplevel() > towers[1].toplevel() else 1
  [frm, to] = [towers[idx], towers[1-idx]]
  return MovingDisk(frm.disks.pop().level,frm,to) \
           if len(frm.disks) > 0 else None
def draw_moving_disk():
  d = moving_disk
  d.step_forward()
  pygame.draw.circle(screen, d.color, (d.pos.x,d.pos.y), d.r)
  pygame.draw.circle(screen, 'black', (d.pos.x,d.pos.y), d.r, 1)
  return d.finish_p()
def turn():
  for t in [moving_disk.frm,moving_disk.to]:
    t.direction = list(filter(
      lambda x: (x != t) and (x != t.direction), [src,aux,dst]))[0]
    t.moving = False
def draw():
  # base drawing
  base_drawing()
  # find two exchange-towers out of three
  flash_poles()
  # start moving
  finish_p = False
  mdisk = moving_disk
  if mdisk == None:
    mdisk = pop_disk(src,aux,dst)
    if mdisk == None:
      finish_p = True
  else:
    if draw_moving_disk():
      turn()
      mdisk = None
  return mdisk, finish_p
# main routine
if __name__ == '__main__':
  src = Tower('Source', NUM_OF_DISKS)
  aux = Tower('Auxiliary',   0, src)
  dst = Tower('Destination', 0, src)
  # In the case of NUM_OF_DISKS is odd, 
  # the src must face the src.
  # Otherwise, the src faces the aux.
  src.direction = dst if len(COLORS) % 2 == 1 else aux
  # the reference to moving disk is stored to this variable.
  moving_disk = None
  screen = setup()
  while True:
    for event in pygame.event.get():
      if event.type == pygame.TEXTINPUT and event.text == 'q':
        pygame.quit()
        exit()
    moving_disk, finish_p = draw()
    if finish_p:
      pygame.quit()
      exit()
    pygame.display.flip()
    pygame.time.delay(30)

特集2 ChatGPTで手軽に実現(Vol.91記載)

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

著者:佐藤 秀輔

対話型AIサービス「ChatGPT」が注目を集めています。特に、2023年3月に登場した「GPT-4」という大規模言語モデル(LLM)を利用可能になってからは自然言語の理解力が飛躍的に向上し、指示に基づいて、さまざまな処理を自動化できるようになっています。本特集では、ChatGPTを個人で活用する例として、家計簿レビューをさせる方法と、API(Application Programming Interface)を利用してWebスクレイピングをさせる方法を紹介します。

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

図1 ランダムな家計簿データを生成するPythonスクリプト

import datetime
import random

itemlist = ['食料品', '外食費', '日用品', '家財道具',
            '交通費', '電気代', '水道代', 'ガス代',
            'ガソリン代', 'その他']

for i in range(366):
  basedate = datetime.datetime(2024, 1, 1)
  date = basedate + datetime.timedelta(days=i)
  item = itemlist[random.randrange(10)]
  amount = random.randrange(100) * 100
  print(f"{date.date()},{date.time()},{item},{amount}")

図10 Webスクレイピング対象となるWebページの例

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>サンプル商品リスト</title>
</head>
<body>
  <h1>商品リスト</h1>
  <div class="product" id="product1">
    <h2>商品名:スニーカー</h2>
    <p>価格:\5000</p>
    <p>評価:4.5 星</p>
  </div>
  <div class="product" id="product2">
    <h2>商品名:バックパック</h2>
    <p>価格:\8000</p>
    <p>評価:4.0 星</p>
  </div>
  <div class="product" id="product3">
    <h2>商品名:水筒</h2>
    <p>価格:\1500</p>
    <p>評価:4.8 星</p>
  </div>
</body>
</html>

図11 Webスクレイピング用のPythonスクリプトの例

import json
from bs4 import BeautifulSoup

# HTMLファイルを開く
with open('sample.html', 'r', encoding='utf-8') as file:
  html_content = file.read()
# BeautifulSoupオブジェクトを作成
soup = BeautifulSoup(html_content, 'lxml')
# 商品情報を抽出
products = soup.find_all('div', class_='product')
product_list = []
for product in products:
  product_name = product.find('h2').text.replace('商品名:', '').strip()
  price = product.find_all('p')[0].text.replace('価格:', '').strip()
  rating = product.find_all('p')[1].text.replace('評価:', '').strip()
  # 各商品情報を辞書として追加
  product_list.append({
    '商品名': product_name,
    '価格': price,
    '評価': rating
  })
# JSON形式で結果を出力
json_output = json.dumps(product_list, ensure_ascii=False, indent=4)
print(json_output)

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

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

004 レポート 統合開発環境「Theia IDE」正式版リリース
005 レポート サイバーエージェントがVLM、新LLM公開
006 製品レビュー パソコン「ASUS Vivobook S 15 S5507QA」
007 NEWS FLASH
008 特集1 Oracle Cloud Infrastructure入門/福島耕平、中村峻大
020 特集2 ChatGPTで手軽に実現/佐藤秀輔 コード掲載
028 特別企画 イノシシ撃退機を作る ハード製作編/米田聡
036 Pythonあれこれ/飯尾淳 コード掲載
042 Markdownを活用する/藤原由来 コード掲載
052 香川大学SLPからお届け!/佐藤楓真 コード掲載
058 中小企業手作りIT化奮戦記/菅雄一
064 これだけは覚えておきたいLinuxコマンド/大津真 コード掲載
073 ユニケージレポート/田中湧也
076 Techパズル/gori.sh
077 コラム「要求工学を取り入れる」/シェル魔人

Vol.91

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

 オラクルといえば、基幹システムでも利用されるリレーショナルデータベース管理システム(RDBMS)製品を開発・販売する企業というイメージがあります。しかし、それだけではありません。「AWS」(Amazon Web Services)や「Microsoft Azure」、「GCP」(Google Cloud Platform)と同等のクラウドサービスとして「Oracle Cloud Infrastructure」(OCI)を提供しています。
 特集1では、このOCIの特徴を分かりやすく解説しています。また、30日間無料で試せる「OCI Cloud Free Tier」を利用してIaaS(Infrastructure as a Service)によるコンピュートインスタンスの立ち上げ方法も紹介しています。実際に触ってみて、データベースだけでないOCIの魅力を感じてください。
 特集2では、生成AIチャット「ChatGPT」の実用例として、支出を分析する「家計簿レビュー」と、Webページから必要な情報を抽出する「Webスクレイピング」の二つを紹介しています。前者は対話形式で分析、後者はAPI(Application Programming Interface)を用いて情報を抽出しています。話題のChatGPTの能力を体験してみてください。
 特別企画では、「Interface」「CQ ham radio」「トランジスタ技術」などの雑誌を出版するCQ出版社の協力を得て、同社が販売する「イノシシ撃退機部品セットVer.1」の組み立て方を紹介しています。農業分野でもITを活用することで、さまざまなメリットが生まれます。このイノシシ撃退機は、イノシシの鳴き声を使うため、安全にイノシシを追い払えます。
 このほか、ユニケージレポートでは、長崎県で2024年6月12~14日に開催された「ソフトウェア・シンポジウム2024」でのユニケージ技術発表と、シェルやシェルスクリプトに関するワークショップを紹介しました。
 今回も読み応え十分のシェルスクリプトマガジン Vol.91。お見逃しなく!

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

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

Vol.91 補足情報

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

特集2 ChatGPTで手軽に実現

 クラウド型家計簿アプリ「Dr.Wallet」のサンプルデータがここからダウンロードできます。家計簿を付けていない人は、こちらを利用してください。なお、本サンプルデータ中のショップ名、電話番号、住所の情報はすべて架空のものです。実在の企業や事業者とは関係ありません。

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

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

  • -->