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

test

シェルスクリプトの書き方入門(Vol.69記載)

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

筆者:大津 真

本連載ではシェルスクリプトの書き方をやさしく紹介します。対象とするシェルは、多くのLinuxディストリビューションが標準シェルとして採用する「Bash」です。第5回は、複数の文字列を柔軟なパターンで指定できる正規表現の基礎について解説します。

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

図2 シェルスクリプト「pref1.sh」の内容

#!/bin/bash

if [[ $# -ne 1 ]]; then
    echo "都道府県名を一つ指定してください"
    exit 1
fi

file=meibo.txt
if grep ":${1}$" $file; then
    count=$(grep -c ":${1}$" $file)
    echo "-- ${1}は${count}件ありました --"
else
    echo "-- ${1}は見つかりませんでした --"
fi

図3 シェルスクリプト「whileRead1.sh」の内容

#!/bin/bash

while read line
do
    echo $line
done < meibo.txt

図4 シェルスクリプト「whileRead2.sh」の内容

#!/bin/bash

cat meibo.txt | while read line
do
    echo $line
done

図5 シェルスクリプト「tokyo.sh」の内容

#!/bin/bash

count=0
grep ":東京$" meibo.txt | while read line
do
    echo "$((++count)):${line}"
done

図6 シェルスクリプト「addpref.sh」の内容

#!/bin/bash

while read line
do
    if echo $line | grep -q ":東京$"; then
        echo $line | sed "s/:東京$/:東京都/"
    elif echo $line | grep -q -e ":大阪$" -e ":京都$"; then
        echo $line | sed "s/:\(..\)$/:\1府/"
    elif echo $line | grep -q ":北海道"; then
        echo $line
    else
        echo $line | sed "s/:\(..*\)$/:\1県/"
    fi
done < meibo.txt

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

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

著者:菅 雄一

 2000年にLinuxサーバーを導入して以来、筆者は、主に費用面での手軽さからOSS(オープンソースソフトウエア)を活用したシステム構築に取り組んできた。だが、2020年になってWindowsサーバーに初めて触れることになった。勤務先の会社が、バッファローの「TeraStation」という法人向けのNAS(Network Attached Storage)製品を購入し、そのOSがWindowsサーバーだったからだ。今回は、そのWindowsサーバー搭載のNAS製品を設定した話を書く。

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

図3 Sambaの設定ファイル(smb.conf)の記述例

[global]
map to guest = bad user
guest account = nobody

[public]
path = /home/samba
guest ok = yes

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

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

著者:石塚 美伶

今回は、音楽の「耳コピ」を支援する音源可視化ツールをPythonで制作する方法について紹介します。制作するツールは、WAVファイルを読み取って音を判別し、その音をピアノの鍵盤で示すGIFアニメーションを生成します。

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

図4 「main.py」ファイルに記述する内容(その1)

import scipy.io.wavfile             # WAVファイルを読み込むために使用
from scipy import signal            # 極大値を求めるために使用
import numpy as np                  # データの整形や高速フーリエ変換に使用
import pandas as pd                 # ピアノの音階辞書を作成するために使用
import matplotlib.pyplot as plt     # 図の作成に使用
import matplotlib.animation as anm  # アニメーション作成に使用
import matplotlib.patches as pat    # 長方形を描画するために使用
import time                         # 時間を表示するために使用

図5 「main.py」ファイルに記述する内容(その2)

wav_filename = "./source.wav"
# 音声ファイルの読み込み
rate, data = scipy.io.wavfile.read(wav_filename)

print("サンプリング周波数:", rate)
print("データ数:", len(data))

if data.ndim < 2:  # 配列の次元数
    print("モノラル")
else:
    print("ステレオ")
    data = np.ravel(data)[::2]  # 連結して偶数要素を抽出する

#(振幅)の配列を作成 (「-1」~「1」の範囲に正規化)
data = data / 32768

# データを0.1秒ごとに分割
split_datas = np.array_split(data, int(len(data) / (rate * 0.1)))

図6 「main.py」ファイルに記述する内容(その3)

count = 0
ex_freqency = []  # 抽出したデータを格納するために用意
for short_data in split_datas:
    ex_freqency.append([])  # データを格納するために空リストを追加
    # フーリエ変換により周波数成分と振幅を取得
    fft_short_data = np.abs(np.fft.fft(short_data))    
    freqList = np.fft.fftfreq(short_data.shape[0], d=1.0/rate)

    maxid = signal.argrelmax(fft_short_data, order=2)  # 極大値を求める
    for i in maxid[0]:
        if fft_short_data[i] > 10 and 25 < freqList[i] < 4200:
            ex_freqency[count].append(freqList[i])  # 周波数を格納
    count += 1

図8 「main.py」ファイルに記述する内容(その4)

piano_dic = pd.read_csv("./piano_dict.csv", encoding="utf-8")
print(piano_dic)

black_keys = piano_dic[piano_dic["scaleNameEn"].str.contains("#")].index
print(black_keys)

count = 0
keys = []  # 含まれる周波数の行
for row in ex_freqency:
    keys.append([])  # 各フレームの周波数を格納するために空リストを追加
    for i in row:
        # 差が最小の音階
        key = piano_dic.loc[abs(piano_dic.frequency - i).idxmin(), "keyNumber"]
        if (key in keys[count]) == False:
            keys[count].append(key)  # 重複してなければ音階を追加
    count += 1
print(keys)

図9 「main.py」ファイルに記述する内容(その5)

fig, ax = plt.subplots(figsize = (10, 2))

# 各フレームの描画
def update(i, fig_title, data_list, ax):
    if i != 0:
        plt.cla()  # 現在描写されているグラフを消去
    ax.axis("off") # 軸と目盛りを削除
    ax.set_xlim(0, 52.1)
    ax.set_ylim(-0.5, 2.5)
    skip = False
    white_count = 0
    plt.title(fig_title + time.strftime("%M:%S", time.gmtime(i * 0.1)))
    for j in range(0, 88):
        if skip == True:
            skip = False  # フラグを降ろす
            continue      # 既に描画した白鍵をスキップする
        if j in black_keys:
            # 黒鍵の右側の白鍵を描画
            color = "white"
            if j + 1 in data_list[i]:
                color = "red"  # 音が鳴っていれば色を赤にする
            # 長方形を作成
            rec = pat.Rectangle(xy = (white_count, 0), \
                                width = 1, height = 1.5, \
                                fc = color, ec = "black")
            ax.add_patch(rec)  # Axesに長方形を追加
            skip = True        # スキップフラグを立てる
            # 白鍵の上に黒鍵を描画
            color = "gray"
            x, y = white_count - 0.3, 0.5
            w, h = 0.6, 1
        else:
            # 白鍵を描画
            color = "white"
            x, y = white_count, 0
            w, h = 1, 1.5
        if j in data_list[i]:
            color = "red"    # 音が鳴っていれば色を赤にする
        # 長方形を作成 
        rec = pat.Rectangle(xy = (x, y), width = w, \
                            height = h, fc = color, ec = "black")
        ax.add_patch(rec)    # Axesに長方形を追加
        white_count += 1     # 白鍵の数をカウント

# アニメーションを生成
ani = anm.FuncAnimation(fig, update, fargs=("Mimicopy ", keys, ax), \
                        interval=100, frames=len(keys))
# GIFファイルとして保存
ani.save("Sample.gif", writer="pillow")

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

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

著者:飯尾 淳

Twitterのトレンドを分析に関する解説の最終回です。これまで、TwitterのトレンドAPIを叩いてトレンドを集め、Twitter Standard search APIでトレンドに関するツイートを収集、そのデータに基づいてトレンドの構造を分析する手法を紹介しました。今回は、その日の主要なトピックは何だったかを可視化する方法を解説します。

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

図7 JSONデータを得るスクリプト(get_data.py)

#!/usr/bin/env python

import json
import urllib.request
import sys
import re

# replace urlbase to the base address of your application
# this script should be called as $ ./get_data.py 2019-02-01
# which means the argument should be a date formatted in YYYY-MM-DD
urlbase = 'http://iiojun.xyz/twt'
jsonapi = '/api/' + sys.argv[1]

word_dict = {}
words = [] 

req = urllib.request.Request(urlbase+jsonapi)
with urllib.request.urlopen(req) as res:
  content = json.loads(res.read().decode('utf8'))
  # loop for labels
  for item in content:
    label = item['label']
    wid = item['id']
    url2 = "{0}/api/trends/{1}".format(urlbase, wid)
    req2 = urllib.request.Request(url2)
    dct = {}
    # loop for words of each label
    with urllib.request.urlopen(req2) as res2:
      content2 = json.loads(res2.read().decode('utf8'))
      for item2 in content2[0]:
        word = item2['word']
        freq = item2['freq']
        dct[word] = freq
        # keep the all words used in the nodes in the array 'words'
        if not word in words: words.append(word)
      # keep the ary of {word, freq} in the dictionary 'word_dict'
      word_dict[label] = dct
print("label", end="")
for item in words:
  print("\t{0}".format(item), end="")
print()

for key in word_dict:
  print(key, end="")
  dct = word_dict[key]
  for item in words:
    freq = dct[item] if item in dct else 0.0
    print("\t%6.3f" % freq, end="")
  print()

図9 コサイン類似度を計算するスクリプト(calc_cos_sim.py)

#!/usr/bin/env python3

import numpy as np
import sys

def cos_sim(v1, v2):
  return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))

lines = sys.stdin.readlines()

lines.pop(0)
wdic = {}
visited = []

for line in lines:
  words = line.split('\t')
  label = words.pop(0)
  wdic[label] = list(map(lambda x: float(x),words))

for key1 in wdic:
  for key2 in wdic:
    visited.append(key2+key1)
    if key1 == key2 or key1+key2 in visited: continue
    print("{0}\t{1}\t{2:9.6f}"
       .format(key1,key2,cos_sim(wdic[key1],wdic[key2])))

図11 dotスクリプトを作成するスクリプト(mk_net.rb)

#!/usr/bin/ruby

word_ary = []
freq_ary = []
node_set = []
node_color = {}
color_tbl = %w(khaki lemonchiffon aliceblue mistyrose coral
  goldenrod aquamarine lavender palegreen gold lightpink 
  plum yellow lightcyan lavenderblush gainsboro 
  yellowgreen lightsteelblue palegoldenrod lightskyblue 
  greenyellow plum cornflowerblue)
th_val = 0.75
mthd = 'fdp'
title = 'topicmap'

STDIN.each {|line|
  (kw1,kw2,freq) = line.split(/\t/)
  word_ary.push(kw1) unless word_ary.include?(kw1)
  word_ary.push(kw2) unless word_ary.include?(kw2)
  if freq.to_f > th_val
    freq_ary.push(line)
    flag = false
    node_set.each {|x|
      if x.include?(kw1) && x.include?(kw2)
        flag = true
        break
      end
      len0 = x.length
      x.push(kw2) if x.include?(kw1) && !x.include?(kw2)
      x.push(kw1) if !x.include?(kw1) && x.include?(kw2)
      if len0 < x.length
        flag = true
        break
      end
    }
    node_set.push([kw1, kw2]) unless flag
  end 
}

def get_set(ary_of_ary, x)
  ret_ary = []
  ary_of_ary.each {|ary|
    ret_ary = ret_ary + ary if ary.include?(x)
  }
  return ret_ary
end
def delete_set(ary_of_ary, x)
  ary_of_ary.each {|ary|
    ary_of_ary.delete(ary) if ary.include?(x)
  }
end

freq_ary.each {|x|
  (kw1,kw2,freq) = x.split(/\t/)
  x1 = get_set(node_set, kw1)
  x2 = get_set(node_set, kw2)
  next if (x1 == x2)
  x3 = x1 | x2
  delete_set(node_set, kw1)
  delete_set(node_set, kw2)
  node_set.push(x3)
}

word_ary.map {|x| node_color[x] = 'white' }

node_set.each_with_index {|value,index|
  i = index % color_tbl.length
  value.map{|x| node_color[x] = color_tbl[i] }
}

print "graph \"#{title}\" {\n"
print " graph [\n    layout = #{mthd}\n  ];\n"

word_ary.each {|x|
  printf "  \"%s\" [ fontname = \"ヒラギノ丸ゴ\"; style = \"filled\"; fillcolor = \"%s\"; fontcolor = \"%s\" ];\n", x, node_color[x], 'black'
}

while (!freq_ary.empty?) do
  (f,t,prob) = freq_ary.shift.split(/\t/)
  printf "  \"%s\" -- \"%s\" [label = \"%4.2f\"];\n", f, t, prob
end

print "}\n"

レッドハットのプロダクト(Vol.69記載)

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

著者:伊藤 智博

最近は昔と比べ、ビジネス要件のレベルが高くなりました。この要件を実現するためさまざまな技術が新たに誕生していますが、それらの技術を開発者が組み合わせて使用するのは非常に困難です。第5回では、これらの技術を組み合わせて高いレベルの要件を簡単に実現するJavaフレームワークの「Quarkus」を紹介します。

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

図7 「quarkus-getting-started/src/main/java/sample/GreetingResource.java」ファイルの内容

package sample;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}

Raspberry Piを100%活用しよう(Vol.69掲載)

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

著者:米田 聡

小型コンピュータボード「Raspberry Pi」(ラズパイ)向けにさまざまな拡張ボードが発売されています。その拡張ボードとラズパイを組み合わせれば、ラズパイでいろいろなことが簡単に試せます。第2回は、赤外線信号の受信が可能な拡張基板を扱います。

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

図3 /boot/config.txtファイルの末尾に追加する2行

dtoverlay=gpio-ir,gpio_pin=4
dtoverlay=gpio-ir-tx,gpio_pin=13

図4 /etc/lirc/lirc_options.confファイルの変更箇所

(略)
driver     = default
device     = /dev/lirc1
(略)

特集2 1日で理解するGoプログラミング(Vol.69記載)

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

著者:KinoCode、ハリー

「エンジニアが次に学びたい言語」のランキングでたびたび上位にランクインしているGo言語。本特集では、Goの特徴やプログラミングについての概要を、1日で学習できるようにコンパクトに解説します。この機会にぜひGoを学んでみてください。

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

図13 挨拶文を表示するサンプルプログラム「greeting.go」のコード

package main
import ("fmt")

func main(){
    fmt.Println("Good morning")
    fmt.Println("Good afternoon")
    fmt.Println("Good evening")
}

特集1 Jetson & Pi 電力測定ボードの使い方(Vol.69記載)

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

著者:北崎 恵凡

ユーザーコミュニティ「Jetson Japan User Group」のメンバーである筆者が設計した、小型コンピュータボードの「Jetson Nano」と「Raspberry Pi」で共通に使える拡張基板「Jetson & Pi 電力測定ボード」をシェルスクリプトマガジンオリジナルとして作成しました。本特集では、このJetson & Pi電力測定ボードの使い方を紹介します。

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

Part1 Jetson & Pi 電力測定ボードを動かす

図7 電源電圧を表示するサンプルプログラム「ina260.py」のソースコード

import smbus
i2c = smbus.SMBus(1)
word = i2c.read_word_data(0x40, 0x02) & 0xFFFF
result = ( (word << 8) & 0xFF00 ) + (word >> 8)
volt = result * 1.25 / 1000

図9 ina260_adafruit.pyのソースコード

import time
import board
import adafruit_ina260

i2c = board.I2C()
ina260 = adafruit_ina260.INA260(i2c)
while True:
    print("Current: %.2f Voltage: %.2f Power: %.2f"
        %(ina260.current, ina260.voltage, ina260.power))
    time.sleep(1)

図12 ina260_plot.pyのソースコード

(略)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
(略)
NUM_BUF_POINTS = 180
PLOT_INTERVAL = 1000

def get_values():
    return([float("{0:.2f}".format(ina260.current / 1000)), float("{0:.2f}".format(ina260.voltage)), float("{0:.2f}".format(ina260.power / 1000))])
(略)
def plot(i):
    global Data

    zone_names = get_names()
    zone_temps = get_values()
    print(zone_temps)
    Data = np.append(Data, np.array([zone_temps]), axis = 0)
    if i >= NUM_BUF_POINTS:
        Data = np.delete(Data, 0, axis = 0)

    plt.cla()
    plt.plot(Data, marker = 'x')
    plt.xlim(0, NUM_BUF_POINTS)
    plt.ylim(0.0, 10.0)
    plt.title('Current Monitor', fontsize = 14)
    plt.xlabel('Time', fontsize = 10)
    plt.ylabel('Current[A],Voltage[V],Power[W]', fontsize = 10)
    plt.tick_params(labelsize=10)
    plt.grid(True)
    plt.legend(labels = zone_names, loc = 'upper left', fontsize = 10)

def main():
    global Data

    zone_names = get_names()
    print(zone_names)

    Data = np.empty((0, len(zone_names)), float)

    fig = plt.figure(figsize=(10, 4))
    ani = animation.FuncAnimation(fig, plot, fargs = (), interval = PLOT_INTERVAL)
    plt.show()
(略)

図14 ssd1306_stats.pyのソースコード

(略)
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
(略)
i2c = busio.I2C(SCL, SDA)
(略)
disp = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
(略)
width = disp.width
height = disp.height
image = Image.new("1", (width, height))
(略)
draw = ImageDraw.Draw(image)
(略)
    cmd = "hostname -I | cut -d' ' -f1"
    IP = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'"
    CPU = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%s MB  %.2f%%\", $3,$2,$3*100/$2 }'"
    MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = 'df -h | awk \'$NF=="/"{printf "Disk: %d/%d GB  %s", $3,$2,$5}\''
    Disk = subprocess.check_output(cmd, shell=True).decode("utf-8")
(略)
    draw.text((x, top + 0), "IP: " + IP, font=font, fill=255)
    draw.text((x, top + 8), CPU, font=font, fill=255)
    draw.text((x, top + 16), MemUsage, font=font, fill=255)
    draw.text((x, top + 25), Disk, font=font, fill=255)
(略)
    disp.image(image)
    disp.show()

図19 ina260_oled.pyのソースコード

(略)
import adafruit_ina260
i2c2 = board.I2C()
ina260 = adafruit_ina260.INA260(i2c2)
(略)
  c = ina260.current
  v = ina260.voltage
  p = ina260.power
  print("Current: %.2f Voltage: %.2f Power: %.2f" %(c, v, p))
(略)
  draw.text((x, top + 0), "Current(mA): " + str("{0:.2f}".format(c)) + ' 	', font=font, fill=255)
  draw.text((x, top + 14), "Voltage(V): " + str("{0:.2f}".format(v)) + ' 	', font=font, fill=255)
  draw.text((x, top + 28), "Power(mW): " + str("{0:.2f}".format(p)) + ' 	', font=font, fill=255)
(略)
  disp.image(image)
  disp.show()
(略)

図21 ssd1306_jp_font.pyのソースコード

(略)
font = ImageFont.truetype('usr/share/fonts/truetype/fonts-japanese-gothic.ttf', 14)
(略)
draw.text((x, top + 0), "てすと", font=font, fill=255)
draw.text((x, top + 14), "日本語", font=font, fill=255)
(略)

図28 imagenet-console_oled.pyのソースコード

(略)
draw.text((0, 0), "分類: " + translator.convert(class_desc), font=font, fill=255)
draw.text((0, 14), "確率: " + "{:0.2f}%".format(confidence * 100), font=font, fill=255)
(略)

図32 imagenet-camera_oled.pyのソースコード

(略)
draw.text((0, 0), "分類: " + translator.convert(class_desc), font=font2, fill=255)
draw.text((0, 14), "確率: " + "{:0.2f}%".format(confidence * 100), font=font2, fill=255)
(略)

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

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

004 レポート MacのApple M1
005 レポート セキュリティゲーム「TERMINAL」
006 NEWS FLASH
008 特集1 Jetson & Pi 電力測定ボードの使い方/北崎恵凡 コード掲載
026 特集2 1日で理解するGoプログラミング/KinoCode、ハリー コード掲載
036 特別企画 Redmineで始めるプロジェクト管理/前田剛
048 Raspberry Piを100%活用しよう/米田聡 コード掲載
051 Hello Nogyo!
052 レッドハットのプロダクト/伊藤智博 コード掲載
062 Docker/桑原滝弥、イケヤシロウ
064 バーティカルバーの極意/飯尾淳 コード掲載
070 法林浩之のFIGHTING TALKS/法林浩之
072 香川大学SLPからお届け!/石塚美伶 コード掲載
076 円滑コミュニケーションが世界を救う!/濱口誠一
078 中小企業手作りIT化奮戦記/菅雄一 コード掲載
084 シェルスクリプトの書き方入門/大津真 コード掲載
092 Techパズル/gori.sh
094 コラム「長続きの秘訣」/シェル魔人

Vol.69

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

 Jetson Japan User Groupの協力を得て、シェルスクリプトマガジン特製オリジナル拡張基板の第3弾となる「Jetson & Pi 電力測定ボード」を開発しました。この拡張基板は、Jetson Nanoの開発キットとRaspberry Pi(ラズパイ)の小型コンピュータボードの両方で利用できます。特集1では、Jetson & Pi 電力測定ボードの概要や使い方などを詳しく紹介します。
 特集2では、人気YouTuberであるKinoCode(キノコード)氏が解説するGoプログラミングです。Goは、米Google社が開発したプログラミング言語です。コンパイル型のために高速な上、プログラムが書きやすく、安全性も高く作られています。最近、最も注目されています。
 特集3では、オープンソースのプロジェクト管理ツール「Redmine」を分かりやすく紹介します。Redmineは「チケット」という単位でさまざまなタスクを管理できます。とても柔軟性が高く、設定次第ではプロジェクト管理だけでなく、さまざまな用途に活用できます。
 このほか、市販の拡張ボードでラズパイを100%利用する記事や、中小企業のシステム管理者の実体験を紹介した奮戦記なども連載として掲載しています。今回も読み応え十分のシェルスクリプトマガジン Vol.69。お見逃しなく!

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

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

Vol.69 補足情報

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

Techパズル

p.92の問題①は、

ではなく、

です。お詫びして訂正いたします。
※ PDF版とKindle版では訂正を反映する予定です。

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

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

  • -->