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

test

ラズパイセンサーボード向けソースコード集

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

シェルスクリプトマガジンとビット・トレード・ワンで共同制作したRaspberry Pi拡張ボード「ラズパイセンサーボード」のソースコード集です。雑誌と一緒にご活用ください。

ソースコードの入手先

2018年12月号(Vol.57)特集1「ラズパイでセンサーを扱う」
2019年2月号(Vol.58)連載「ラズパイセンサーボードで学ぶ 電子回路の制御」第5回
・2019年4月号(Vol.59)連載「ラズパイセンサーボードで学ぶ 電子回路の制御」第6回(コードなし)
2019年6月号(Vol.60)連載「ラズパイセンサーボードで学ぶ 電子回路の制御」第7回
2019年8月号(Vol.61)連載「ラズパイセンサーボードで学ぶ 電子回路の制御」第8回
2019年10月号(Vol.62)連載「ラズパイセンサーボードで学ぶ 電子回路の制御」第9回
2019年12月号(Vol.63)連載「ラズパイセンサーボードで学ぶ 電子回路の制御」第10回
・2020年2月号(Vol.64)連載「ラズパイセンサーボードで学ぶ電子回路の制御」第11回(コードなし)
・2020年6月号(Vol.66)連載「ラズパイセンサーボードで学ぶ電子回路の制御」第13回
2020年8月号(Vol.67)連載「ラズパイセンサーボードで学ぶ電子回路の制御」最終回


※関連記事掲載時に追加していきます。

※ラズパイ入門ボード向けソースコード集はこちら

「Visual Studio Code」を便利に使う(Vol.60掲載)

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

著者:あかね

 米Microsoft社発のオープンソースエディタ「Visual Studio Code」には「Extension」と呼ばれる機能拡張用のソフトウエアが多数提供されています。本連載では便利なExtensionの使い方を中心に紹介します。第3回は、Windowsの OS標準のCL(I シェル環境)「PowerShell」で記述したスクリプトをデバックするためのExtensionを紹介します。

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

図9 サンプルスクリプト(test.ps1)

# Variable declaration
$KaigenDate #改元日
$Wareki #和暦
$CultureInfo #フォーマット前の情報

$CultureInfo = New-Object system.Globalization.CultureInfo("ja-JP");
$CultureInfo.DateTimeFormat.Calendar = New-Object System.Globalization.JapaneseCalendar

# Main
$KaigenDate= Get-Date -Date '2019/05/01'
$Wareki=$KaigenDate.ToString("ggy年M月d日", $CultureInfo)
Write-Host '改元日は'$Wareki'です!'

図16 引数を必要とするサンプルスクリプト

# WarekiDisp という名前の関数。引数に与えた日付(yyyymmdd)を和暦表示します。
param([string]$arg_date)

# Variable declaration
$conv_Date #引数で指定されたものをDateに設定
$Wareki #和暦
$CultureInfo #フォーマット前の情報

$CultureInfo = New-Object system.Globalization.CultureInfo("ja-JP");
$CultureInfo.DateTimeFormat.Calendar = New-Object System.Globalization.JapaneseCalendar

# Main
$conv_Date=[datetime]::ParseExact($arg_date, "yyyyMMdd", $null);
$Wareki=$conv_Date.ToString("ggy年M月d日", $CultureInfo)

Write-Host $Wareki'です!'

Webアプリケーションの正しい作り方(Vol.60記載)

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

著者:しょっさん

 ソフトウエアを正しく作るために、エンジニアたちはどんなことを知らなければならないのでしょうか。実際のコードを使って、より良くしていくためのステップを考えてみましょう。第1回は、動くソフトウエアとは何かを解説していきます。

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

図1 経費精算Webアプリケーション

const express = require('express');
const app = express()
const models = require('./models');
const expenses = models.expense;
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const users = {
  'user01': 'p@ssw0rd',
  'user02': 'ewiojfsad'
};

app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
  secret: 'secret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    maxAge: 24 * 30 * 60 * 1000
  }
}));

app.get('/login', (req, res) => {
  res.send('<h1>LOGIN</h1><form action="/login" method="post">ユーザーID:<input type="text" name="user" size="40"><br />パスワード<input type="password" name="password"><input type="submit" value="ログイン">');
});

app.post('/login', (req, res) => {
  if (eval("users." + req.body.user) === req.body.password) {
    req.session.user = req.body.user;
  }
  res.redirect('/');
});

app.post('/expense', (req, res) => {
  expenses.create(req.body)
    .then(() => {
      res.redirect('/');
    });
});

app.get('/', (req, res) => {
  const user = req.session.user || '名無しの権兵衛';
  res.writeHead(200, { "Content-Type": "text/html" });
  res.write(<h1>Hello ${user}</h1><table><tr><th>ID</th><th>申請者名</th><th>日付</th><th>経費タイプ</th><th>経費詳細</th><th>金額</th></tr>);
  expenses.findAll()
    .then(results => {
      for (let i in results) {
        res.write(<tr><td>${results[i].id}</td><td>${results[i].user_name}</td><td>${results[i].date}</td><td>${results[i].type}</td><td>${results[i].description}</td><td>${results[i].amount}</td></tr>);
      }
      res.write('</table><a href="/login">ログイン</a><a href="/submit">経費入力</a>');
      res.end();
    });
});

app.get('/submit', (req, res) => {
  const user = req.session.user || '名無しの権兵衛';
  res.send(<h2>経費入力</h2><form action="/expense" method="post">申請者名:<input type="text" name="user_name" value="${user}"><br />日付:<input type="date" name="date"><br />経費タイプ:<input type="text" name="type"><br />経費詳細:<input type="text" name="description"><br />金額:<input type="number" name="amount"><br /><input type="submit" value="経費申請">);
});

const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(http://localhost:${port});
})

特集1 ラズパイで電子回路の作成と制御(Vol.60掲載)

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

著者:麻生二郎

 電子回路を触ってみたい、作ってみたい、制御してみたいと思ったときに、人気の小型コンピュータボード「Raspberry Pi」(ラズパイ)と組み合わせるのが意外と簡単です。本特集では、市販のモジュールと、ラズパイを使って電子回路
の作成や制御を素早く実現する方法を紹介します。

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

図5 制御プログラム(bme280_sensor.py)

#!/usr/bin/env python3

import smbus2
import bme280
i2c = smbus2.SMBus(1)

data = bme280.sample(i2c, 0x76)
print('気温 :' + str(round(data.temperature, 1)) + '度')
print('湿度 :' + str(round(data.humidity, 1)) + '%')
print('気圧 :' + str(round(data.pressure, 1)) + 'hPa')

図8 制御プログラム(atd1602_lcd.py)

#!/usr/bin/env python3

from lcd_st7032 import ST7032

lcd = ST7032()
lcd.write("Shellscript")
lcd.setCursor(1, 0)
lcd.write([0xbc, 0xaa, 0xd9, 0xbd, 0xb8, 0xd8, 0xcc, 0xdf, 0xc4])

図11 制御プログラム(bh1750_sensor.py)

#!/usr/bin/env python3

import smbus2
from i2csense.bh1750 import BH1750

bus = smbus2.SMBus(1)
sensor = BH1750(bus)

sensor.update()
print(sensor.light_level)
print(sensor.current_state_str)

図14 制御プログラム(rain_sensor.py)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

try:
  while True:
    rain = GPIO.input(17)
    if rain == 0:
      print("雨が降り始めました")
      GPIO.cleanup()
      break
except KeyboardInterrupt:
  GPIO.cleanup()

図17 制御プログラム(fire_sensor.py)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

try:
  while True:
    fire = GPIO.input(17)
    if fire == 0:
      print("火災が発生しました")
      GPIO.cleanup()
      break
except KeyboardInterrupt:
  GPIO.cleanup()

図20 制御プログラム(pir_sensor.py)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

try:
  while True:
    pir = GPIO.input(17)
    if pir == 1:
      print("人が侵入しました")
      GPIO.cleanup()
      break
except KeyboardInterrupt:
  GPIO.cleanup()

図26 制御プログラム(doorphone.py)

#!/usr/bin/env python3

from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)

try:
  for i in range(0,3):
    GPIO.output(17, GPIO.HIGH)
    GPIO.output(17, GPIO.LOW)
    sleep(2)
except KeyboardInterrupt:
  GPIO.cleanup()

図28 制御プログラム(sound_sensor.py)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

try:
  while True:
    if GPIO.wait_for_edge(17, GPIO.RISING):
      print("指パッチン!")
      GPIO.cleanup()
      break
except KeyboardInterrupt:
  GPIO.cleanup()

図31 制御プログラム(soil_sensor.py)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

try:
  while True:
    rain = GPIO.input(17)
    if rain == 1:
      print("水分量が足りません")
      GPIO.cleanup()
      break
except KeyboardInterrupt:
  GPIO.cleanup()

図34 制御プログラム(slope_sensor.py)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

try:
  while True:
    if GPIO.wait_for_edge(17, GPIO.FALLING):
      print("傾きました")
      GPIO.cleanup()
      break
except KeyboardInterrupt:
  GPIO.cleanup()

図38 制御プログラム(distance_sensor.py)

#!/usr/bin/env python3

import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(27, GPIO.OUT)
GPIO.setup(17, GPIO.IN)

GPIO.output(27, GPIO.LOW)
time.sleep(0.3)
GPIO.output(27, GPIO.HIGH)
time.sleep(0.00001)
GPIO.output(27, GPIO.LOW)

try:
  while GPIO.input(17) == 0:
    palse_start = time.time()
  while GPIO.input(17) == 1:
    palse_end = time.time()
  palse_width_time = palse_end - palse_start
  distance = palse_width_time * 1000000 / 58
  print("距離は {0} cmです".format(distance))
  GPIO.cleanup()
except KeyboardInterrupt:
  GPIO.cleanup()

図42 制御プログラム(music_box.py)

#!/usr/bin/env python3

from time import sleep
import RPi.GPIO as GPIO
import sys

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)

for _ in range(args):
  GPIO.output(17, GPIO.HIGH)
  sleep(0.01)
  GPIO.output(17, GPIO.LOW)
  sleep(0.05)
GPIO.cleanup()

Vol.60

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

 ラズパイのおかげで電子工作が身近になってきています。とはいえ、誰でもすぐに始められるわけではありません。特集1では、市販されている12種類の電子回路モジュールを使って、やさしく、そして簡単に、ラズパイで電子回路の作成と制御ができる方法を紹介しています。こんなセンサーがほしい、液晶パネルに文字を表示したい人も満足できる内容です。
 特集2では、Webアプリケーションのプログラミング言語「PHP」をやさしく解説しています。短い、簡単なコードを書きながら、データベース管理システムを利用したWebアプリケーションを作成していきます。
 特集3では、本格的な業務システムをシェルスクリプトで構築できる「ユニケージ開発手法」を紹介しています。なぜシェルスクリプトで業務システムが作れるのか、ユニケージ開発手法の専用コマンドのusp Tukubaiとは何か、テキストファイルを利用したデータ管理の仕組みなど、入門者にはぴったりの内容となっています。
 特別企画では、ソフトウエア開発における「コーディング」「ビルド」「実装」「テスト」という一連の作業を楽にする「ツールチェーン」を取り上げました。IBM Cloudにおけるツールチェーンの構築・利用方法を具体的に分かりやすく紹介しています。
 このほか、新連載「Webアプリケーションの正しい作り方」、人気連載の「ラズパイセンサーボードで学ぶ電子回路の制御」なども掲載しています。
 今回も読み応え十分のシェルスクリプトマガジン Vol.60。お見逃しなく!

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

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

バーティカルバーの極意(Vol.60掲載)

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

著者:飯尾淳

 本連載の第5 回(Vol.51、2017 年12 月号)で、バーティカルバー(垂直棒)が3 本立っているという理由から「ハノイの塔」というパズルを取り上げました。今回は、そのときの考察を思い出しつつ、ハノイの塔を解くプログラムを再び考えます。
 ただし、今回は三つの塔を「上から見下ろした」状態、俯瞰(ふかん)で考えます。至ってシンプルなルールで解ける面白さを、動作の可視化プログラムを用いて確認してみましょう。

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

図3 sketch.jsを書き換えたコード 

const COLORS = [ 'crimson', 'forestgreen', 'yellow',
   'royalblue', 'saddlebrown', 'hotpink', 'darkorange',
   'darkmagenta' ];
const N_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] };

class Position {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class Disk {
  constructor(level) {
    this.level = level;
    this.color = COLORS[level];
    this.r = (DISK_R-POLE_R)*(N_DISKS-level)
                / N_DISKS + POLE_R;
  }
}

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;
    var rx, ry;
    [rx,ry] = POSITIONS[name];
    this.pos = new Position(rx*C_WIDTH, ry*C_HEIGHT);
  }
}

var src = new Tower('Source', N_DISKS);
var aux = new Tower('Auxiliary',   0, src);
var dst = new Tower('Destination', 0, src);
// 円盤の数(N_DISKS)が奇数のときはDestinationを、
// そうでないときはAuxiliaryを向くようにする
src.direction = (N_DISKS % 2 == 1) ? dst : aux;

function setup() {
  createCanvas(C_WIDTH, C_HEIGHT);
  frameRate(30);
}

function draw() {
  // put drawing code here
}

図5 追加した描画に関するコード部分

class Disk {
  constructor(level) {
(略)
  }

  draw(pos) {
    stroke('black');
    fill(this.color);
    ellipse(pos.x, pos.y, 2*this.r);
  }
}

class Tower {
  constructor(name, disks, direction=null) {
(略)
  }

  draw() {
    var pos  = this.pos;
    var pos2 = this.direction.pos;
    var sx, sy, dx, dy, r;

    // 円盤を描く
    this.disks.forEach(function(d) { d.draw(pos) })

    // 支柱を描く
    stroke('brown');
    fill('white');
    ellipse(pos.x, pos.y, 2*POLE_R);

    // 向きを描く
    stroke('navy');
    [sx, sy] = [pos.x,  pos.y ];
    [dx, dy] = [pos2.x, pos2.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 setup() {
  createCanvas(C_WIDTH, C_HEIGHT);
  frameRate(30);
}

function draw() {
  background('beige');
  [src, aux, dst].forEach(function(t) { t.draw(); })
}

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

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

004 レポート Windows Subsystem for Linux 2
005 レポート LibrePlanet 2019開催
006 NEWS FLASH
008 特集1 ラズパイで電子回路の作成と制御/麻生二郎 コード掲載
028 特集2 PHP超入門/柏岡秀男 コード掲載
038 特集3 ユニケージ開発手法入門/當仲寛哲 コード掲載
051 姐のNOGYO
052 特別企画 ツールチェーン/小薗井康志、川副博、古川正宏 コード掲載
074 ラズパイセンサーボードで学ぶ 電子回路の制御/米田聡 コード掲載
078 人間とコンピュータの可能性/大岩元
080 Webアプリケーションの正しい作り方/しょっさん コード掲載
088 close/桑原滝弥・イケヤシロウ
090 中小企業手作りIT化奮戦記/菅雄一
096 香川大学SLPからお届け!/山下賢治 コード掲載
101 「Visual Studio Code」を便利に使う/あかね コード掲載
106 円滑コミュニケーションが世界を救う!/濱口誠一
108 バーティカルバーの極意/飯尾淳 コード掲載
114 法林浩之のFIGHTING TALKS/法林浩之
116 機械学習のココロ/石井一夫 コード掲載
121 漢のUNIX/後藤大地
128 UNIXの歴史を振り返る/古寺雅弘
134 ユニケージ新コードレビュー/岡田健 コード掲載
136 Techパズル/gori.sh
140 コラム「令和はサバイバルの時代」/シェル魔人

特別企画 ツールチェーン(Vol.60掲載)

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

 著者:小薗井康志、川副博、古川正宏

 「コーディング」「ビルド」「実装」「テスト」という一連のソフトウエア開発作業を、「ツールチェーン」を使って、効率良く、そして楽にしてみませんか。クラウドサービス「IBM Cloud」が提供するツールチェーンで、その便利さを味わってみましょう。

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

図21 サンプルで用意されているテストスクリプト

#!/bin/bash
export PATH=/opt/IBM/node-v6.7.0/bin:$PATH
# Push app
export CF_APP_NAME="staging-$CF_APP"
cf push "${CF_APP_NAME}"
push_result=$?
export APP_URL=https://$(cf app $CF_APP_NAME | grep -e urls: -e routes: | awk '{print $2}')
# View logs
#cf logs "${CF_APP_NAME}" --recent
deploy_status="pass"
if [ $push_result -ne 0 ]; then
deploy_status="fail"
fi
npm install -g grunt-idra3
idra --publishdeployrecord --env=$LOGICAL_ENV_NAME --status=$deploy_status --appurl=$APP_URL

特集2 PHP超入門(Vol.60掲載)

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

著者:柏岡秀男

 「PHP」(PHP: Hypertext Preprocessor)は、Webアプリケーションの開発によく使われているプログラミング言語です。本特集では、WindowsやmacOSにPHPプログラムの実行環境やWebサーバー、DBMSサーバーをインストールできる「MAMP」というソフトウエアを使って、PHPプログラミングを手軽に体験する方法を紹介します。これを機会にぜひPHPプログラミングを始めてみてください。

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

図1 現在時刻を表示するWeb ページをPHPで作成した例

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title> 現在時刻</title>
</head>
現在時刻は
<?php
  echo date("H:i:s")
?>
です

図10 helloworld.php

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
 <title>Hello world</title>
</head>
<?php echo "Hello, World!"; ?>

図11 表示したWeb ページのソースコード

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>Hello world</title>
</head>
Hello, World!

図12 sample1.php

<?php
  $a = 1;
  $b = 2;
  echo $a + $b;
?>

図13 以下のサンプルコードの冒頭に付加するコード

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title><?php echo __FILE__; ?></title>
</head>

図14 sample2.php

<?php
  $a = " シェルスクリプト";
  $b = " マガジン";
  echo $a . $b;
?>

図15 sample3.php

<pre>
<?php
  $a = array(1,2,3,4,5);
  $b = array("a" => 1,"b" => "abc","c" => "123");
  $c[0] = 123;
  $c[1] = $b;
  var_dump($a);
  var_dump($b);
  var_dump($c);
  echo $a[1];
  echo "\n";
  echo $b["c"];
  echo "\n";
?>
</pre>

図17 if 文の基本構文

<?php
  $a = 1;
  if($a > 10) {
    echo "a は10 より大きい";
  }
?>
<?php
  $a = 1;
  if($a > 10) {
    echo "a は10 より大きい";
  } else {
    echo "a は10 以下";
  }
?>

図18 input.php

<form method="post" action="input.php">
  <input type=text name="a">
  <input type=submit>
</form>
<?php
  var_dump($_POST);
?>

図19 sample_input.php

<form method="post" action="sample_input.php">
  <input type=text name="a">
  <input type=submit>
</form>
<?php
  if($_POST["a"] > 10 ) echo "10 より大きい";
?>

図20 sample_input2.php

<form method="post" action="sample_input2.php">
  <input type=text name="a" >
  <input type=submit>
</form>
<?php
  if (isset($_POST["a"])) {
    if($_POST["a"] > 10 ) {
      echo "10 より大きい";
    } else {
      echo "10 以下";
    }
  } else {
    echo " 数字を入力してください";
  }
?>

図25 connect.php

<?php
  try {
    $dbh = new PDO(
      "mysql:host=localhost;dbname=sampledatabase;charset=utf8",
      "phpuser","testpassword"
    );
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  } catch (Exception $e) {
    die(" データベース接続失敗 ".$e->getMessage());
  }
  echo " 接続できました";
?>

図26 input.html

<!DOCTYPE html>
<head>
  <title>TODO データの入力画面</title>
</head>
<form method="post" action="add.php">
  <input type=text name="todo">
  <input type=submit>
</form>
TODO データを入力してください

図27 add.php

<?php
  var_dump($_POST);
  try {
    $dbh = new PDO(
      "mysql:host=localhost;dbname=sampledatabase;charset=utf8",
      "phpuser","testpassword"
    );
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = "INSERT INTO sample (todo) VALUES (:todo_value)";
    $stmt = $dbh->prepare($sql);
    $todo = urldecode($_POST["todo"]);
    $stmt->bindValue(":todo_value", $todo, PDO::PARAM_STR);
    $stmt->execute();
    echo " データを登録しました";
  } catch (Exception $e) {
    die(" データベース接続失敗 ".$e->getMessage());
  }
?>

図28 list.php

<?php
  try {
    $dbh = new PDO(
      "mysql:host=localhost;dbname=sampledatabase;charset=utf8",
      "phpuser","testpassword"
    );
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = "SELECT * FROM sample WHERE status IS NULL";
    $res = $dbh->query($sql);
    foreach($res as $row) {
      echo htmlspecialchars($row["todo"], ENT_QUOTES);
      echo "<br />";
    }
  } catch (Exception $e) {
    die(" データベース接続失敗 ".$e->getMessage());
  }
?>

図30 list2.php

<?php
  try {
    $dbh = new PDO(
    "mysql:host=localhost;dbname=sampledatabase;charset=utf8",
    "phpuser","testpassword"
    );
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $sql = "SELECT * FROM sample WHERE status IS NULL";
    $res = $dbh->query($sql);
    foreach($res as $row) {
      $id = htmlspecialchars($row["id"], ENT_QUOTES);
      echo htmlspecialchars($row["todo"], ENT_QUOTES);
    echo "<a href='update.php?id=" . $id . "'> 完了</a><br />";
    }
  } catch (Exception $e) {
    die(" データベース接続失敗 ".$e->getMessage());
  }
?>

図31 update.php

<?php
  try {
    $dbh = new PDO(
      "mysql:host=localhost;dbname=sampledatabase;charset=utf8",
      "phpuser","testpassword"
    );
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = "UPDATE sample SET status = 1 WHERE id = :id_value";

    $stmt = $dbh->prepare($sql);
    $id = (int) $_GET["id"];
    $stmt->bindValue(":id_value", $id, PDO::PARAM_INT);
    $stmt->execute();
    echo " データを更新しました";
  } catch (Exception $e) {
    die(" データベース接続失敗 ".$e->getMessage());
  }
?>

香川大学SLPからお届け!(Vol.60掲載)

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

著者:山下賢治

 今回は、Webブラウザでアクセスできる予定共有アプリの作成方法を紹介します。Webアプリケーションフレームワークの「Ruby on Rails」と、JavaScriptのライブラリである「FullCalendar」を組み合わせることで、マウス操作で予定の追加や変更が可能な予定共有アプリを手軽に作成できます。

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

図2 ルーティング設定

Rails.application.routes.draw do
  resources :calendar, only: [:index]
end

図3 アプリのViewを作成する手順

<div id="calendar"></div>
$(document).on 'turbolinks:load',->
  $('#calendar').fullCalendar({})
  return
$(document).on 'turbolinks:before-cache',->
  $('#calendar').empty()
  return
/*
  *= require_tree .
  *= require_self
  *= require fullcalendar
*/
//= require moment
//= require jquery
//= require fullcalendar
//= require fullcalendar/locale-all
//= require fullcalendar/lang/ja
$(function(){
  $('#calendar').fullCalendar({});
})

図5 ルーティング設定の変更

Rails.application.routes.draw do
  resources :calendar, only: [:index]
  resources :schedules, only: [:index, :create]
end

図6 登録データをJSON形式で取り出すコードを追加

class SchedulesController < ApplicationController
  def index
    schedules = Schedule.all
    respond_to do |format|
      format.json {
        ender json:
        schedules.to_json()
      }
    end
  end
end

図7 登録済みのデータを表示するコードを追加

//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .
//= require moment
//= require jquery
//= require fullcalendar
//= require fullcalendar/locale-all
//= require fullcalendar/lang/ja
$(function(){
  $('#calendar').fullCalendar({
    events: '/schedules.json'
  });
})

図9 「app/assets/javascripts/application.js」のコード改造例

$('#calendar').fullCalendar({
  selectable: true,
  selectHelper: true,
  draggable: true,
  select: function(start, end) {
    var title = prompt("予定名");
    var scheduleData;
    if ( title ) {
      scheduleData = {
        title: title,
        start: start,
        end: end
      };
      $('#calendar').fullCalendar('renderEvent', scheduleData, true);
      createSchedule(scheduleData);
    }
    $('#calendar').fullCalendar('unselect')
  },
  events: '/schedules.json'
});
createSchedule = function(scheduleData) {
  $.ajax({
    type: 'POST',
    url: "/schedules",
    data: {
      title: scheduleData.title,
      start: String(scheduleData.start),
      end: String(scheduleData.end),
      authenticity_token: $("#authenticity_token").val()
    }
  }).done(function(data) {
    alert("登録しました");
  }).fail(function(data) {
    alert("登録失敗しました");
  });
};

図10 「app/views/calendar/index.html.erb」ファイルに追加する記述

<%= hidden_field_tag "authenticity_token", form_authenticity_token %>

図11 「app/controllers/schedules_controller.rb」ファイルに追加する記述

def create
   Schedule.create(
     title: params[:title],
     start: DateTime.parse(params[:start]),
     end: DateTime.parse(params[:end])
   )
 end

ユニケージ新コードレビュー(Vol.60掲載)

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

著者:岡田健

 ユニケージでは、小さな道具の「コマンド」をシェルスクリプトで組み合わせて、さまざまな業務システムを構築しています。本連載では、毎回あるテーマに従ってユニケージによるシェルスクリプトの記述例を分かりやすく紹介します。第7回は、書き方のルールとなるお作法と分かりやすいコードの書き方について解説します。

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

図1 売上計算するシェルスクリプト

cat SALES                       |
#  1:店舗 2:商品No 3:日付 4:売数
#  5:売上 6:割引
join1 key=2 PRICE               | # 原価 / 売価を連結
#  1:店舗 2:商品No 3:原価 4:売価
#  5:日付 6:売数   7:売上 8:割引
join1 key=2 CATEGORY            | # 部門を連結
#  1:店舗 2:商品No 3:部門 4:原価
#  5:売価 6:日付   7:売数 8:売上
#  9:割引
lcalc '$3,$7,$8,$8-$7*$4'       | # 売数 / 売上 / 荒利計算
#  1:部門 2:売数 3:売上 4:粗利
msort key=1                     | # 部門でソート
sm2 1 1 2 4                     | # 売数 / 売上 / 荒利集計
sm5 1 1 2 4                     | # 合計行の付加
divsen 2 3 4                    | # 千で除算
divsen 3 4                      | # 千で再除算
lcalc '$1,$2,$3,$4,100*$4/$3'   | # 荒利率を求める
#  1:部門   2:売数 3:売上 4:粗利
#  5:粗利率
marume 5.1                      | # 四捨五入
join2 key=1 CATEGORY_NAME       | # カテゴリ名の連結
#  1:部門 2:部門名 3:売数 4:売上
#  5:粗利 6:粗利率
comma 3 4 5                     | # カンマ編集
keta                            | # 桁そろえ
keisen +e                       | # 罫線を引く
cat header -                      # 出力

図2 awkによる長いコードが挿入されたシェルスクリプト

cat ZAIKO             |
#  1:商品CD     2:規格CD     3:拠点CD   4:サイズCD
#  5:産地CD     6:ブランドCD 7:仕入先CD 8:発注先CD
#  9:在庫発生日 10:製造日    11:販売日  12:数量
(略)

図3 在庫を扱うシェルスクリプトの先頭部分

cat ZAIKO             |
#  1:商品CD     2:規格CD     3:拠点CD   4:サイズCD
#  5:産地CD     6:ブランドCD 7:仕入先CD 8:発注先CD
#  9:在庫発生日 10:製造日    11:販売日  12:数量
cjoin2 key=1 SHOHIN - |
#  1:商品CD   2:商品名      3:規格CD     4:拠点CD
#  5:サイズCD 6:産地CD      7:ブランドCD 8:仕入先CD
#  9:発注先CD 10:在庫発生日 11:製造日    12:販売日
#  13:数量
cjoin2 key=3 KIKAKU - |
#  1:商品CD   2:商品名    3:規格CD      4:規格名
#  5:拠点CD   6:サイズCD  7:産地CD      8:ブランドCD
#  9:仕入先CD 10:発注先CD 11:在庫発生日 12:製造日
#  13:販売日  14:数量
(略)

図4 各種マスターを使って在庫に名称を挿入するシェルスクリプトの一部

cat ZAIKO             |
#  1:商品CD     2:規格CD     3:拠点CD   4:サイズCD
#  5:産地CD     6:ブランドCD 7:仕入先CD 8:発注先CD
#  9:在庫発生日 10:製造日    11:販売日  12:数量
cjoin2 key=1 SHOHIN - |
#  1:商品CD   2:商品名      3:規格CD     4:拠点CD
#  5:サイズCD 6:産地CD      7:ブランドCD 8:仕入先CD
#  9:発注先CD 10:在庫発生日 11:製造日    12:販売日
#  13:数量
cjoin2 key=3 KIKAKU - |
#  1:商品CD   2:商品名    3:規格CD      4:規格名
#  5:拠点CD   6:サイズCD  7:産地CD      8:ブランドCD
#  9:仕入先CD 10:発注先CD 11:在庫発生日 12:製造日
#  13:販売日  14:数量
(略)

図5 図4の修正版

cat ZAIKO              |
#  1:商品CD     2:規格CD     3:拠点CD   4:サイズCD
#  5:産地CD     6:ブランドCD 7:仕入先CD 8:発注先CD
#  9:在庫発生日 10:製造日    11:販売日  12:数量
self 0 1               |
cjoin2 key=NF SHOHIN - |
delf NF-1              |
#  1:商品CD     2:規格CD     3:拠点CD   4:サイズCD
#  5:産地CD     6:ブランドCD 7:仕入先CD 8:発注先CD
#  9:在庫発生日 10:製造日    11:販売日  12:数量
#  13:商品名
self 0 3               |
cjoin2 key=NF KIKAKU - |
delf NF-1              |
#  1:商品CD     2:規格CD     3:拠点CD   4:サイズCD
#  5:産地CD     6:ブランドCD 7:仕入先CD 8:発注先CD
#  9:在庫発生日 10:製造日    11:販売日  12:数量
#  13:商品名    14:規格名
(略)

特集3 ユニケージ開発手法入門(Vol.60掲載)

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

著者:當仲寛哲

業務システムを開発するときの選択肢として「ユニケージ
開発手法」があります。ユニケージ開発手法は、Linux/UNIX
のコマンドを基盤としたものです。「シェル魔人」と「りな」
の会話を通して、ユニケージ開発手法で業務システムがど
う作られるのかを理解しましょう。

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

図4 ユニケージ開発手法によるシェルスクリプトの記述例

#!/bin/bash -vx
#
# JIKANTAI.CGI 時間帯別販売情報参照システムのCGI スクリプト
(略)
# POST データの受け取り
if [ ! -z "$CONTENT_LENGTH" ] ; then
dd bs=$CONTENT_LENGTH |
cgi-name -n_ -s_ > $tmp-name
ERROR_CHECK
else
(略)
# はめ込み用日付情報の作成
echo $day $cday                            |
# 1: 日付 2: 比較日コード
join1 key=2 $tmp-cdaynum -                 |
# 1: 日付 2: 比較日コード 3: 比較日
delf 2                                     |
# 1: 日付 2: 比較日
dayslash --output "yyyy 年_mm 月_dd 日" 1 2 |
cat > $tmp-day
ERROR_CHECK
# 現在時刻
curtime="$(dayslash -d $todayhms --output 'yyyy 年 mm 月 dd 日 HH:MM:SS')"
##################################################
# HTML 作成
cat $apld/HTML/JIKANTAI.HTML               |
mojihame -lSHOP_RECORDS - $tmp-data        |
mojihame -lSYOHIN_INFO - $tmp-info         |
mojihame -lSEARCH_DATE - $tmp-day          |
formhame -s_ -n_ - $tmp-name               |
calsed '###CURRENT_TIME###' "$curtime"     |
calsed '###USER###' "$USER"                |
cat > $tmp-html

図19 セールスレポートを作成するシェルスクリプト(demo)

#!/bin/bash -x
join1 key=2 PRICE SALES       | # 原価/ 売価を連結
join1 key=2 CATEGORY          | # カテゴリを連結
lcalc '$3,$7,$8,$8-$7*$4'     | # 売数/ 売上/ 荒利計算
msort -p4 key=1               | # カテゴリでソート
sm2 1 1 2 4                   | # 売数/ 売上/ 荒利集計
sm5 1 1 2 4                   | # 合計行の付加
divsen 2 3 4                  | # 千で除算
divsen 3 4                    | # 千で再除算
lcalc '$1,$2,$3,$4,100*$4/$3' | # 荒利率を求める
marume 5.1                    | # 四捨五入
join2 key=1 CATEGORY_NAME     | # カテゴリ名の連結
comma 3 4 5                   | # カンマ編集
keta                          | # 桁そろえ
keisen +e                     | # 罫線を引く
cat header -                    # 出力
exit 0

図21 コメントを入れた例

#!/bin/bash
# 商品コードに、原価/売価を連結
join1 key=2 PRICE SALES       |
# 商品コードにカテゴリーコードを連結
join1 key=2 CATEGORY          |
# [ レイアウト ]
# 1:店コード 2:商品コード 3:カテゴリコード 4:仕入価格 5:販売価格
# 6:販売日付 7:販売個数 8:販売金額 9:値引金額
# カテゴリコード、売数、売上、粗利(売上-売数x仕入価格)を計算
lcalc '$3,$7,$8,$8-$7*$4'     |
# [ レイアウト ]
# 1:カテゴリコード 2:販売個数 3:販売金額 3:粗利金額
msort -p4 key=1               | # カテゴリでソート
sm2 1 1 2 4                   | # 売数 / 売上 / 粗利集計
sm5 1 1 2 4                   | # 合計行の付加
divsen 2 3 4                  | # 千で除算
divsen 3 4                    | # 千で再除算 (売上・粗利は百万円単位)
# 粗利率を求める
lcalc '$1,$2,$3,$4,100*$4/$3' |
# [ レイアウト ]
# 1:カテゴリコード 2:販売個数 3:販売金額 4:粗利金額 5:粗利率
# 粗利率を四捨五入
marume 5.1                    |
# カテゴリ名の連結
join2 key=1 CATEGORY_NAME     |
# [ レイアウト ]
# 1:カテゴリコード 2:カテゴリ名 3:販売個数 4:販売金額 5:粗利金額
# 6:粗利率
comma 3 4 5                   | # カンマ編集
keta                          | # 桁そろえ
keisen +e                     | # 罫線を引く
cat header -                    # 出力
exit 0

図25 最新のレベル4を出力する

echo LV1.101.*      |
xargs cat           |
msort key=1@NF      |
upl key=1@NF LV4 -

Vol.60 補足情報

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

目次

連載コラム「香川大学SLPからお届け!」の回のタイトルに誤りがありました。「バーコードリーダーを使って手軽なデータ収集システム」ではなく、「Ruby on RailsとFullCalendarで予定共有アプリを作る」です。 お詫びして訂正いたします 。

読者プレゼント

右上のQRコードが誤っていました。正しいQRコードは以下です。 お詫びして訂正いたします 。

姐のNOGYO

左上の別掲記事の「1998年」は「1989年」の誤りです。 お詫びして訂正いたします 。

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

センサーボードで学ぶ電子回路の制御(Vol.60掲載)

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

著者:米田聡

 シェルスクリプトマガジンでは、小型コンピュータボード「Raspberry Pi」(ラズパイ)向けのセンサー搭載拡張ボード「ラズパイセンサーボード」を制作しました。第7 回では、I2C のインタフェースに接続するI/Oエキスパンダ「MCP23017」でGPIO 端子を増やす方法を紹介します。

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

図9 MCP23017のGPIOを読み書きするためのPythonライブラリ(mcpgpio.py)

from smbus import SMBus

class MCPGPIO():
  __IODIR  = [0x00, 0x01] # レジスタ番号
  __GPPU   = [0x0C, 0x0D]
  __GPIO   = [0x12, 0x13]
  __OLAT   = [0x14, 0x15]

  INPUT       = 1
  OUTPUT      = 0
  INPUTPULLUP = 3

  HIGH        = 1
  LOW         = 0

  def __init__(self,address = 0x20):
    self.bus = SMBus(1)
    self.addr = address

  def setup(self, pin, dir):
    if pin < 16:
      dir = self.bus.read_byte_data(self.addr,self.__IODIR[int(pin/8)])
      dir &= ~(0x01 << int(pin % 8))
      dir |= (dir & 1) << int(pin % 8)
      self.bus.write_byte_data(self.addr, self.__IODIR[int(pin/8)], dir)
      if (dir & 1) ==  1:
        pu  = self.bus.read_byte_data(self.addr,self.__GPPU[int(pin/8)])
        pu &= ~(0x01 << int(pin % 8))
        pu |= ((dir >> 1) & 1) << int(pin % 8)
        self.bus.write_byte_data(self.addr, self.__GPPU[int(pin/8)], pu)
    
  def input(self, pin):
    r = 0
    if pin < 16:
      gp = self.bus.read_byte_data(self.addr, self.__GPIO[int(pin/8)])
      r = (gp >> int(pin%8) & 1)
    return r

  def output(self, pin, val):
    if pin < 16:
      gp = self.bus.read_byte_data(self.addr, self.__GPIO[int(pin/8)])
      gp &= ~(0x01 << int(pin % 8))
      gp |= (val & 1) << int(pin % 8)
      self.bus.write_byte_data(self.addr, self.__GPIO[int(pin/8)], gp)

  @property
  def gpioa(self):
    return  self.bus.read_byte_data(self.addr, self.__GPIO[0])
    
  @gpioa.setter
  def gpioa(self, value):
    self.bus.write_byte_data(self.addr,self.__GPIO[0], value)
    
  @property
  def gpiob(self):
    return  self.bus.read_byte_data(self.addr, self.__GPIO[1])

  @gpiob.setter
  def gpiob(self, value):
    self.bus.write_byte_data(self.addr,self.__GPIO[1], value)

機械学習のココロ(Vol.60掲載)

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

著者:石井一夫

 今回は、機械学習を実施する際に一番問題となる過学習の問題を取り上げます。過学習というのは、機械 学習のモデルが、ある特定の状況に過剰適合してしまい、新たなサンプルに対してうまく予測ができなくなるという現象です。

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

図5 L1 正則化を実施するコード

l1_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l1(0.001),
                    activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l1(0.001),
                    activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])
l1_model.compile(optimizer='adam',
                loss='binary_crossentropy',
                metrics=['accuracy', 'binary_crossentropy'])
l1_model_history = l1_model.fit(train_data, train_labels,
                               epochs=20,
                               batch_size=512,
                               validation_data=(test_data, test_labels),
                               verbose=2)

図6 過学習の評価結果を表示するコード

plot_history([('baseline', baseline_history),
               ('l1', l1_model_history)])

第4回 ファイルサーバーを作る

投稿日:2019.05.21 | カテゴリー: 記事

 インターネット上にあるサーバー以外で、最も利用されているのが「ファイルサーバー」です。「NAS」(Netowork Attached Storage)や「ネットワーク対応HDD」「ネットワークハードディスク」などとも呼ばれています。このファイルサーバーですが、Linuxパソコンがあれば比較的簡単に構築できます。
 そこで今回は、Linux上にファイルサーバーを構築するシェルスクリプトを作成しましょう(図1)。

図1 シェルスクリプトでファイルサーバーを構築

第3回 写真を整理する

投稿日:2019.05.7 | カテゴリー: 記事

 スマートフォンならいつでもどこでも気軽に写真を撮影できます。ただ、その気軽に撮った写真データのせいでスマートフォンのストレージ容量の空き容量が少なくなることがあります。また、新しいスマートフォンを買い換えるときは、多量にある写真データを移し変えることは困難です。これらの場合、写真データをパソコンなどにバックアップする人も多いでしょう。バックアップの際、ファイル名を書き換えることができると便利です。

 そこで今回は、パソコンに保存した写真データのファイル名を書き換えるシェルスクリプトを作成します。

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

  • -->