「Raspberry Piで学ぶ ROSロボット入門」という本を書きました

Pocket
LINEで送る

ロボットにラズパイを載っけてROSで動かすという流行りもの全部乗せの節操のない本を書きました。3月30日に出ます。以前の日経Linuxの連載をまとめて、原型を留めないほどROS化したものです。本日校了ということで、9月から12月までは執筆、1月からは書き直しや校正と、充実した地獄が終わりました。

 

 

まさか自分がROSの本を書くとは思っていませんでした。私のROSに関するコントリビューションは、たまにROS Wikiを翻訳するくらいです。あんまりROSのコミュニティーに仁義が切れてないのは、別のコミュニティーをやってる身としては褒められたものではないという認識なのですが、日経Linuxの内容を強化する上でROSが避けられず、自分も真正面から扱うことにした次第です。

本の中ではこんなことをしています。

内容は大学の講義や実習を想定しています。4月からの講義にはギリギリですが、ぜひ本を手にとっていただければと。

Pocket
LINEで送る

【問題のみ】第27回sedこわいシェル芸勉強会

Pocket
LINEで送る

解答例はこちら

問題で使うファイル等

GitHubにあります。ファイルは

https://github.com/ryuichiueda/ShellGeiData/tree/master/vol.27

にあります。

クローンは以下のようにお願いします。

$ git clone https://github.com/ryuichiueda/ShellGeiData.git

イントロ

環境

対象とするsedはGNU sedだけに絞っています。解答例はUbuntu Linux 16.04 で作成。Macの場合はcoreutilsをインストールの上、gsedをつかいましょう。GSD系の人は玄人なので各自対応のこと。

Q1

次のechoの出力について、偶数番目の文字だけ大文字にしてください。できたら、奇数番目の文字だけ大文字にしてください。

$ echo abcdefghijklmn

Q2

seq 1 100から始めてsedだけでFizzBuzzをやってみましょう。

Q3

次の出力について、3行目を7行目の下に移動してください。

$ seq 1 10

Q4

次のコードのmainとahoの位置を入れ替えてください。

$ cat aho.cc 
#include <iostream>
using namespace std;

int main(int argc, char const* argv[])
{
	aho();
	return 0;
}

void aho(void)
{
	cout << "aho" << endl;
}

Q5

seq 1 10 | から始めて次のような出力を作ってください。

2
1
4
3
6
5
8
7
10
9

Q6

echo 1から始めて次のような出力を作ってください。

1
11
111
1111
11111
111111
1111111
11111111
111111111
1111111111

Q7

aというファイルをtouch等で作り、次の縛りでa1, a2, a3, …, a10というファイルをaからコピーして作ってください。縛り1と縛り2を独立した別々の問題として解き、その後縛り1,2を両方満たす解を考えてみましょう。

  • 縛り1: 使うコマンドはseq、cp、sedだけ
  • 縛り2: ワンライナー中で数字を使わない

Q8

echo 1 | から始めて、あとはsedだけで次のような出力を得てください。

1
11
111
1111
11111
11111
1111
111
11
1
Pocket
LINEで送る

近況: 日経Linux、RoboCup2016(世界大会)出る、投稿論文通った他

Pocket
LINEで送る

おかげさまでいいニュースが多くて忙しくしています。現在は日経Linuxの6月号の原稿と、推薦をもらったので和文の投稿論文を執筆中です。どちらも3/31締め切り。死ぬ。

日経Linux4月号発売

今月の特集は「大門」だそうで、一体何のことでしょうか。都営線の地味な駅のことでしょうか。大門刑事でしょうか。それとも私の実家の方で作っている素麺のことでしょうか。Linuxとの関係は何なのでしょうか。(叱られるぞ。)

ファイル 2016-03-09 22 02 10

何の特集かは商品を手にとって是非ご自身の目でお確かめください。

あ、今月の私の連載は「ジャイロを使って比例制御でロボットをまっすぐ走らせる」です。

別冊も、あまりにもド直球なタイトルですが、中身が気になりますね。

CIT Brains @Homeが世界大会に出場します

私もお菓子配り係として参加している家事ロボット作るぞチーム「CIT Brains @Home」が、結成からわずか4ヶ月で世界大会に出ることになりました。皆様おめでとうございます。今年の世界大会(RoboCup2016)は、6月に東ドイツのライプチヒで行なわれます。秘密警察が怖いですが、西側のお菓子をたくさん持ち込んで民主化の起爆剤にする所存です。とりあえず税関でお菓子に法外な関税をかけられないように注意します。

真面目な話をすると、チームではスポンサーを募集しております。本来ならこちらから回ってお願いすべき話なのですが、万が一ご興味があれば@ryuichiuedaにお知らせくださいませ。家事ロボットは人の声を認識する、腕や台車部分を自動制御する、複数のPCをロボットに載せた状態で安定させて動かす等、様々な技術の検証や統合にとても良い課題です。もちろん、掃除以外もこなすルンバを作るという話ですので、今後の需要も非常に期待できます。チームの結成当初から一緒に戦っていただけるパートナーを探しております。

もちろん、ロボットにステッカーを貼ったりウェブサイトにバナーを貼ったりという、影響力はわずかかもしれませんが直接的な特典も検討いたします。

投稿論文通った

復帰後2本目の投稿論文の採択通知をいただきました。プレプリントをアップしました。こんなやつです。

内容は自分の博士論文を少し進めたもので、でっかいPCで数値計算で求めたロボットの行動規則がでかくてマイコンに載らないのでどうやって圧縮しようかという話です。マイコン制御の倒立振子を作って実機実験をやりたかったのですが、自分に作る腕がないので制御対象はシミュレーションの二重振子になりました。

その他

そろそろ4月のシェル芸勉強会の支度をしないと・・・

寝る。

Pocket
LINEで送る

GitHubのWikiの変更をHubot経由でSlackに通知

Pocket
LINEで送る

シェル芸勉強会の次の日でかなり疲れているのですが、「GitHubのWikiを複数人で編集し、その変更をSlackに飛ばしたい」というニッチな需要ができたので工作活動してました。Slackの標準の機能には、GitHubのWikiの更新を受け取る手段が2016年2月14日現在、無いようです。(あったらすぐ教えてください!30分くらい探してSlack側に受け口が見つからなくてキレてやっちまいました。)issueやpullリクエストの通知機能はあるんですが・・・。

ということで、HubotにGitHubからJSONを飛ばして、Hubotで解釈してSlackに飛ばすことにしました。Hubotについては、次のサイトを参考にインストールを行いました。環境はVPSのUbuntu 14.04上です。

チャットボットでチーム開発効率化入門(1):GitHub製フレームワークHubotの概要とインストール、チャットアプリと連携する基本的な使い方 (1/2) – @IT チャットボットでチーム開発効率化入門(1):GitHub製フレームワークHubotの概要とインストール、チャットアプリと連携する基本的な使い方 (1/2) - @IT
CentOSにHubotを導入してSlackと連携させる – Qiita CentOSにHubotを導入してSlackと連携させる - Qiita

また、CoffeeScriptを書いた時はHubot経由でGitHubのイベントを通知する | SPACEMARKET BLOGを参考にさせていただきました。掲載されているコード(GitHubのissue等をTwitterに飛ばすもの)を、GitHubのwikiをslackに飛ばすように改造しました。

以下はちょっと端折ってますが手順です。

Hubotを召喚する

必要なものを上のサイトを参考にインストール後、適当なディレクトリ(自分の場合は~/HUBOT/GITHUB)を作り、その下で次のコマンドを打ちます。

yo hubot

すると、こんな感じで根掘り葉掘り聞かれます。AAがアホっぽいです。いや、なんでもありません。

$ yo hubot
                     _____________________________  
                    /                             \ 
   //\              |      Extracting input for    |
  ////\    _____    |   self-replication process   |
 //////\  /_____\   \                             / 
 ======= |[^_/\_]|   /----------------------------  
  |   | _|___@@__|__                                
  +===+/  ///     \_\                               
   | |_\ /// HUBOT/\\                             
   |___/\//      /  \\                            
         \      /   +---+                            
          \____/    |   |                            
           | //|    +===+                            
            \//      |xx|                            

? Owner Ryuichi UEDA <aho@gmail.com>
? Bot name github
? Description A simple notifier for GitHub wiki
? Bot adapter (campfire) slack

間違えてはいけないのは

? Bot adapter (campfire) slack

の一箇所です。

hubotの起動スクリプトを作る

ディレクトリの下のbin/hubotがHubotの起動シェルスクリプトです。これを次のように書き換えます。PORTは、HubotがGitHubからデータを受け取るときに使うポート番号です。

このスクリプトは最後のforeverでサーバに常駐化します。常駐化するとデバッグで止めたり動かしたりするのが面倒なので、
デバッグの時はコメントアウトしている#exec…を使うと良いでしょう。こっちを使うとCtrl+cで止まります。

各種設定

上のスクリプトで次のようになっているところは、自分の環境に合わせて書き換える必要があります。

export HUBOT_SLACK_TOKEN=xxxxxx
export HUBOT_GITHUB_SECRET=yyyyyyy

HUBOT_SLACK_TOKENはSlackのHubotの設定ページに、次のようにトークンが表示されているはずなので、これをコピペして使います。

1455450034

HUBOT_GITHUB_SECRETは、GitHubの連携したいリポジトリのWebhookの設定で、「Add webhook」を押すと、次のように表示されるので、ここの「Secret」に適当なトークンを入れて使います。

1455450001

私は次のような感じで作りました。

$ cat /etc/* | md5sum 2> /dev/null
b720a34fb302c401e5146cefe1ae656d  -

Secretの二つ上にある「Payload URL」は、http://:<ポート番号>/github/webhookにしておきます。このURLの「github」というのはHubotの名前です。

また、リポジトリのどんな変化に対して通知を受け取るかは、「Which events would you like to trigger this webhook?」という項でいじります。「Gollum」というのがWiki関係の通知に相当します。

Hubotスクリプト

こんな風に書きました。Hubotのディレクトリ下のscriptsディレクトリに<なんとかかんとか>.coffeeという名前で置いておくと、bin/hubotを実行すると動き出します。isCorrectSignatureの部分は上に挙げた3番目のブログのコードを整形して使い回しています。

次の部分(19行目)がSlackにデータを投げている部分です。「lab-github」というのは、Slackのチャンネルですので、用途に合わせて変更しましょう。毎度ハードコーティングで申し訳なく・・・

robot.messageRoom 'lab-github', message

スクリプト自体はパースされたJSONのデータを切った貼ったしているだけなので、なんとなく分かる人なら、どんどんいじっていけると思います。GitHubが送ってくるJSONの実物は、さっきのGitHubのリポジトリwebhook設定ページにあります。

Slackには、次のように通知が入ります。(ちょっとデバッグ中のメッセージもありますが。)

スクリーンショット 2016-02-14 21.44.46

表示される情報がURLだけで味気ないので、もうちょっと改良の余地あり。いや、これくらいの方がかえっていいのかも・・・。

寝る。

Pocket
LINEで送る

【問題と解答】第21回未経験者大歓迎!誰でも働けるアットホームな職場ですシェル芸勉強会

Pocket
LINEで送る

問題だけのページはこちら

問題で使うファイル等

GitHubにあります。ファイルは

https://github.com/ryuichiueda/ShellGeiData/tree/master/vol.21

にあります。

クローンは以下のようにお願いします。

$ git clone https://github.com/ryuichiueda/ShellGeiData.git

環境

今回はUbuntu Linuxで解答例を作りましたので、BSD系、Macな方は以下の表をご参考に・・・。

Mac,BSD系 Linux
gdate date
gsed sed
tail -r tac
gtr tr
gfold fold

イントロ

補記

最近あまり本の宣伝をしていないのでシェルプログラミング実用テクニックから問題を持ってきました。

Q1

ShellGeiData/vol.21/Q1のbba.pdfからテキストを抽出して標準出力に出してください。

解答例

例題のファイルの日本語にはFlateDecodeという圧縮がかかっていますが、これを解凍する一般的なコマンドは見つかりませんでした。ですのでpdf用のコマンドを紹介するだけで・・・。FlateDecodeの解凍コマンドはzlibを使うと自作はできる模様。

###poppler-utilsをインストール###
$ sudo apt-get install poppler-utils
###あとはlessとかpdftotextとか###
$ less bba.pdf | cat
  群馬のシャブばばあ




hoge.txt[2016/02/09 22:30:32]
$ pdftotext -q bba.pdf -
群馬のシャブばばあ

hoge.txt[2016/02/09 22:30:32]

Q2

次のデータはShift JIS(cp932)の固定長データです。

$ cat anydata.cp932 
00000001??ӹ޷?ݺ?*******214413051100000002ʰ????ݸ*********114413018800000003???ӷ?ݺ?********210413093100000004??ݷ?ݺ?*********234413000800000005???ް??׳??޷?ݺ?331413090000000006??Э????ݾ޲??ݺ?1234130981

次のようなUTF-8のテキストに変換してください。

00000001ハナモゲギンコウ*******2144130511
00000002ハードバンク*********1144130188
00000003コドモギンコウ********2104130931
00000004ハタンギンコウ*********2344130008
00000005アンダーグラウンドギンコウ3314130900
00000006バミューダメンゼイギンコウ1234130981


解答

###Shift JISの半角は1バイトなのでUTF-8に変換する前に折り返すと楽です。###
$ cat anydata.cp932 | fold -b35 | nkf -wLux
00000001ハナモゲギンコウ*******2144130511
00000002ハードバンク*********1144130188
00000003コドモギンコウ********2104130931
00000004ハタンギンコウ*********2344130008
00000005アンダーグラウンドギンコウ3314130900
00000006バミューダメンゼイギンコウ1234130981

###1行の長さを調べるときは仕様書を見るか、規則性を見つけて折り返して長さを調べる###
$ cat anydata.cp932 | sed 's/[0-9]\{10\}/&\n/g' |
 LANG=C awk '{print length($0)}'
35
35
35
35
35
35
1
1

Q3

2016年の日曜日を全て列挙してください。

解答

GNU dateの-fを使うと楽です。

$ seq 20160101 20161231 | date -f - 2> /dev/null | grep 日曜日
2016年  1月  3日 日曜日 00:00:00 JST
2016年  1月 10日 日曜日 00:00:00 JST
2016年  1月 17日 日曜日 00:00:00 JST
...
2016年 12月 18日 日曜日 00:00:00 JST
2016年 12月 25日 日曜日 00:00:00 JST
###Tsukubaiを使う例###
$ mdate -e 20160101 20161231 | tr ' ' '\n' | yobi 1 | awk '$2==0'
20160103 0
20160110 0
20160117 0
...
20161218 0
20161225 0

Q4

次のデータファイル

001 あみだばばあ
002 砂かけばばあ
003 ******
004 尾崎んちのババア

に、次の新しいデータ

002 *******
003 群馬のシャブばばあ
005 純愛ババア学園

を反映して

001 あみだばばあ
002 *******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園

というデータを出力してください。

解答

$ sort -ms -k1,1 newdata data | uniq -w 3
001 あみだばばあ
002 *******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園

Q5

GitHubのvol.21/Q5にある次の二つのシェルスクリプトのデバッグをしてください。

$ cat ./a.bash 
#!/bin/bash

echo Hell
###実行すると変なバグ###
$ ./a.bash 
./a.bash: 行 1: #!/bin/bash: そのようなファイルやディレクトリはありません
Hell
$ cat b.bash 
#!/bin/bash

ls ˜/
###ホームディレクトリが表示されない###
$ ./b.bash 
ls: ˜/ にアクセスできません: そのようなファイルやディレクトリはありません

解答

a.bashについては「BOM付きUTF-8」という凶悪なフォーマットなので発見はバイナリの理解が大きな助けになります。が、とりあえずnkfに通せばBOMは取れます。たまにWindowsからやってきます。

###調べるとUTF-8と出るので発見が遅れる。###
$ nkf -g a.bash 
UTF-8
###xxdで見ると頭に変なバイト列。###
$ xxd -ps a.bash 
efbbbf23212f62696e2f626173680a0a6563686f2048656c6c0a
###ただし、見なくてもnkfで除去できる。###
$ nkf -wLux a.bash > a
$ chmod +x a
$ ./a
Hell

b.bashは、チルダがUTF-8のマルチバイト文字になっていて、~/がホームディレクトリに変換されません。このスクリプトには他にマルチバイト文字がないので、次のようなワンライナーでチルダがおかしいことを発見できます。

$ iconv -c -f utf-8 -t ascii b.bash | diff - b.bash 
3c3
< ls /
---
> ls ˜/

Q6

次の拡張正規表現をワンライナーで基本正規表現に変換してください。括弧の中の数字は数字の回数の文字列の繰り返しに展開してください。

$ cat extended 
a+h{5}(ho){10}[0-9]+

解答

ゴリゴリです。

$ cat extended | sed 's/[+}]/&\n/g' | sed 's/\(.*\)+/\1\1*/' |
 tr '{}()' '    ' |
 awk 'NF==2{for(i=1;i<=$2;i++){printf $1};print ""}NF==1' |
 tr -d '\n' | xargs
aa*hhhhhhohohohohohohohohoho[0-9][0-9]*

Q7

GitHubのvol.21/Q7にあるテキストについて、各段落の文字数を数えてください。

解答

改行をとって数える対象を1行にまとめる方針が簡単です。解答例はロケールが日本語で、awkがgawkである等、いろいろ制約がありますが・・・。

$ cat text | tr -d '\n' | sed 's/ /\n/g' |
 awk '{print length($1),$1}'
0 
15 恥の多い生涯を送って来ました。
353 自分には、人間の生活というものが、...にわかに興が覚めました。
103 また、自分は子供の頃、...とばかり思っていました。

Q8

GitHubのvol.21/Q8にある1350369599.Vfc03I4682c8M940114.remoteから添付ファイルを抽出して画像を復元してください。二つありますが別々に処理して構いません。

解答

まず、何行目から何行目までがデータなのか調べます。

$ grep -n -C 1 -- -- 1350369599.Vfc03I4682c8M940114.remote 
(略)
59:--047d7b621ee6cf83c604cc276bb3
60-Content-Type: image/jpeg; name="CHINJYU.JPG"
--
665-0000000000000000000000000000001//9k=
666:--047d7b621ee6cf83c604cc276bb3
667-Content-Type: image/jpeg; name="IMG_0965.JPG"
--
77341-xk9On61jS6VNFJqFxdoIZYbWK6QALsnJbBjHYcc4GT2IHJrGhUevkZ1MNypPuf/Z
77342:--047d7b621ee6cf83c604cc276bb3--

で、その範囲を抽出して変換します。一つめの画像の切り出しの例だけ示しておきます。

###出力の範囲を見ながらデータを切り出す###
$ sed -n '60,665p' 1350369599.Vfc03I4682c8M940114.remote |
 sed -n '6,$p' | base64 -d > a.jpg
###ImageMagickのidentifyコマンドでちゃんと画像になっているか確認###
ueda@remote:~/GIT/ShellGeiData/vol.21/Q5$ identify a.jpg 
a.jpg JPEG 261x261 261x261+0+0 8-bit DirectClass 34.2KB 0.010u 0:00.019
###さらにavplayで画像を見る###
$ avplay a.jpg

Pocket
LINEで送る

【問題のみ】第21回未経験者大歓迎!誰でも働けるアットホームな職場ですシェル芸勉強会

Pocket
LINEで送る

解答はこちら。

問題で使うファイル等

GitHubにあります。ファイルは

https://github.com/ryuichiueda/ShellGeiData/tree/master/vol.21

にあります。

クローンは以下のようにお願いします。

$ git clone https://github.com/ryuichiueda/ShellGeiData.git

環境

今回はUbuntu Linuxで解答例を作りましたので、BSD系、Macな方は以下の表をご参考に・・・。

Mac,BSD系 Linux
gdate date
gsed sed
tail -r tac
gtr tr
gfold fold

イントロ

補記

最近あまり本の宣伝をしていないのでシェルプログラミング実用テクニックから問題を持ってきました。

Q1

ShellGeiData/vol.21/Q1のbba.pdfからテキストを抽出して標準出力に出してください。

Q2

次のデータはShift JIS(cp932)の固定長データです。

$ cat anydata.cp932 
00000001??ӹ޷?ݺ?*******214413051100000002ʰ????ݸ*********114413018800000003???ӷ?ݺ?********210413093100000004??ݷ?ݺ?*********234413000800000005???ް??׳??޷?ݺ?331413090000000006??Э????ݾ޲??ݺ?1234130981

次のようなUTF-8のテキストに変換してください。

00000001ハナモゲギンコウ*******2144130511
00000002ハードバンク*********1144130188
00000003コドモギンコウ********2104130931
00000004ハタンギンコウ*********2344130008
00000005アンダーグラウンドギンコウ3314130900
00000006バミューダメンゼイギンコウ1234130981


Q3

2016年の日曜日を全て列挙してください。

Q4

次のデータファイル

001 あみだばばあ
002 砂かけばばあ
003 ******
004 尾崎んちのババア

に、次の新しいデータ

002 *******
003 群馬のシャブばばあ
005 純愛ババア学園

を反映して

001 あみだばばあ
002 *******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園

というデータを出力してください。

Q5

GitHubのvol.21/Q5にある次の二つのシェルスクリプトのデバッグをしてください。

$ cat ./a.bash 
#!/bin/bash

echo Hell
###実行すると変なバグ###
$ ./a.bash 
./a.bash: 行 1: #!/bin/bash: そのようなファイルやディレクトリはありません
Hell
$ cat b.bash 
#!/bin/bash

ls ˜/
###ホームディレクトリが表示されない###
$ ./b.bash 
ls: ˜/ にアクセスできません: そのようなファイルやディレクトリはありません

Q6

次の拡張正規表現をワンライナーで基本正規表現に変換してください。括弧の中の数字は数字の回数の文字列の繰り返しに展開してください。

$ cat extended 
a+h{5}(ho){10}[0-9]+

Q7

GitHubのvol.21/Q7にあるテキストについて、各段落の文字数を数えてください。

Q8

GitHubのvol.21/Q8にある1350369599.Vfc03I4682c8M940114.remoteから添付ファイルを抽出して画像を復元してください。二つありますが別々に処理して構いません。

Pocket
LINEで送る

【メモ】ImageMagick(convertコマンド)で3枚以上の画像を合成する

Pocket
LINEで送る

単なるメモですが日本語で手っ取り早いエントリーがなかったので。以下のドキュメントを読んでやってみました。

http://www.imagemagick.org/script/command-line-options.php?#evaluate-sequence

バージョンはこれです。Macでやってます。

$ convert --version
Version: ImageMagick 6.9.2-3 Q16 x86_64 2015-10-06 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules 
Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib

この5枚を合成します。これもImageMagickで連結しました。($ convert +append *.png ../a.png)

b

実行。maxのほかにmeanとかminとかあります。

uedamb:tmp ueda$ convert *.png -evaluate-sequence max ../a.png

できたのがこれ。

a

時間を食ってしまったけどこれで論文が完成する・・・。

Pocket
LINEで送る

寿司デバイス

Pocket
LINEで送る

昨日のコレが、講義で使うにはあまりにもアレだったので、ちょっとマイルドな「寿司デバイス」も作りました。

スクリーンショット 2016-01-02 10.51.06

リポジトリはココ

昨日のコレと組み合わせると、危険なワンライナーと寿司とビールが飛び交う世界がお楽しみいただけます。

スクリーンショット 2016-01-02 11.36.43

Enjoy 寿司.

Pocket
LINEで送る

30億のデバイスで走るとやばい危険シェル芸デバイス作った

Pocket
LINEで送る

年が明けました。昨年は

という騒ぎがありましたが、今年はシェル芸ポリスとして、荒ぶるシェル芸人を取り締まるふりをする所存です。出動!ミニスカポリス。

違います。

本題

今日は年明けの講義のためにデバイスドライバの例を書いておりました。ただ、今日は元日です。酒を飲みながら書いていたので、なんでこうなったかよくわからんのですが、気がついたら危険シェル芸のコマンドを吐く擬似デバイスができていました。

READMEを読んでも良く分からないと思いますので、解説を。

擬似デバイスとは

/dev/nullとか/dev/urandomとか、裏側に機械がくっついてないのに機械とのインタフェースの役割をするもののことです。/dev/nullとかのことは「デバイスファイル」と呼びます。「擬似デバイス」というのは「デバイスファイルを入出力口にして働く仮想の機械」というニュアンスの言葉です。

UNIX屋さんなら何か調査するときに、デバイスファイルを次のように使ったりします。

###コマンドの性能を測る(画面に文字を出して遅くならないように/dev/nullを使う)###
$ time grep -r hoge ~/ > /dev/null
###128バイトの大きさのファイルを作る###
uedamb:~ ueda$ head -c 128 /dev/urandom > a
uedamb:~ ueda$ ls -l a
-rw-r--r-- 1 ueda staff 128  1  1 22:32 a

要はデータを吸い込んだり、生成したりする特別なファイルということになります。なぜコマンドやデーモンによるサービスの体裁を取らないかというと、ファイルの方がcatやリダイレクトで簡単に使えるからです。データハンドリングはファイルシステムで、というのはUNIXがUNIXであるための大前提のようなものです。日経Linuxの去年の連載では、「ロボットでも基本はファイル入出力で」というテーマで執筆したのですが、それもこういうUNIXの考え方を意識したものでした。

どうやって作るのか

デバイスファイルの裏側にはデバイスドライバがいます。デバイスドライバをしかるべき方法でコーディングすれば、擬似デバイスを作ることができます。字を受けたときにどんな反応をするかをデバイスドライバ内に書けば、機械の代わりにそのコードが仕事をしてくれるわけです。本物の機械のためのデバイスドライバを書くときは(と言っても私は経験がほとんどありませんが)、デバイスドライバ内で機械のレジスタをいじることになります。

デバイスドライバはカーネルの一部として動くので、デバイスドライバのコードはカーネルを書くように書かねばなりません。printfとかmallocが使えなかったり、いろいろ面倒なので、その分敷居は少し高くなります。

あんまり詳しくは書けないのですが、コードをざっと見ていただければと。

使い方

今のところ、Ubuntu Linux 14.04でしか動作確認してません。今日作り始めたので当たり前ですが・・・。ということで、以下の操作をUnbuntuか、もし試していただけるなら別のLinux環境で行います。apt-getでgitとかmakeとかをインストールする必要があります。また、Linuxのヘッダファイルがないとコンパイルできないので、もしかしたらそれもapt-getする必要があるかもしれません。私はサーバ版でコンパイルしましたが、ヘッダはすでにあったのでapt-getする必要はありませんでした。

$ git clone https://github.com/ryuichiueda/KikenShellGeiDevice.git
$ cd KikenShellGeiDevice/
$ make

次のように「kiken.ko」というファイルができていたらOK。

$ ls kiken.ko
kiken.ko

デバイスドライバは、insmodというコマンドでカーネルに組み込みます。

$ sudo insmod kiken.ko
###カーネルから外したかったら以下のように###
$ sudo rmmod kiken 

次のように、「/dev/kiken0」というファイルができているはずです。

$ ls -l /dev/kiken0 
crw------- 1 root root 249, 0  1月  1 23:03 /dev/kiken0
###読み込みできるようにしておきましょう###
$ sudo chmod +r /dev/kiken0 

使う(危険)

なんだか薄くて真面目な解説になっちまってましたがここからが本番です。headで打ち切ってますが、アレなワンライナーがランダムに出続けます。ネタはココから。

$ cat /dev/kiken0 | head
sudo yum -y remove python*
sudo yum -y remove python*
echo '部長はヅラ' >> /etc/motd
echo ログ集計乙wwwww>> /var/log/httpd/access_log
rsync -av --delete /tmp/ ~/
yes | xargs -P 0 yes
for x in `seq 1 1 10000`; do wall '我はroot。神だ' ; done
crontab -r
echo {a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}{a..z}
rsync -av --delete /tmp/ ~/

危険極まりない。本当に何を考えているんだ。

パイプと相性抜群

とりあえず、自分のマシンを壊していいのなら、次のような使い方が標準になると思います。何の標準か知らんけど。

$ cat /dev/kiken0 | sudo bash

試さない方が良いです。何の責任も取れないことはGPLのライセンスの中に書いてあリ・・・。

安全に試す方法

かと言って何も試さないのも面白くないので、次のワンライナーを提示しておきます。grepにつけた-aは、grepがバイナリとして危険シェル芸を扱ってしまうので、文字列として扱ってくれと明示的に指示するためのオプションです。

$ cat /dev/kiken0 | grep -a 高須 | bash 

今後

オプションを充実させたり、標準入力から読み込んだ文字を関数の名前にしてfork爆弾を返す機能を実装する・・・っていうか講義の準備します。

本当に冗談です。

寝る。

20160102追記: テスト用VPSサーバにインストール。いい感じだ。

スクリーンショット 2016-01-02 10.05.42

20160102追記: Raspberry Pi 2用のMakefileを追加。

Pocket
LINEで送る

ダイナミックDNSを使わずにシェル芸等々で自宅のサーバへアクセスするシステム作った

Pocket
LINEで送る

(追記: 早速「VPSに向かってトンネル掘っとけよ!とUSP友の会で尻を突かれております。トンネル掘られそうです。」。あと、cronの頻度が高いと先方のサービスに蹴られる可能性があるのと、かと言って頻度を下げるとケーブルテレビ系だとちと辛いという話になってます。NTT, AUはIPがほとんど変わらないというのが経験上、言えることですが、保証はないです。)

久しぶりにサーバいじりネタ。本当は今週学会1つと講義2つの準備があって、講義の準備が1つ済んでいないが、子供がギャーギャー言っている環境だと趣味ぐらいしか手が動かないので・・・

やりたいこと

自宅に外からアクセスできるGitサーバ、ファイルサーバが欲しい。個人情報は置かない。自宅には光回線。IPアドレスが変わるがダイナミックDNSを使うほどでもない。

自作自宅(と言っても仕事用)サーバ

(笑)

ファイル 2015-12-13 20 35 51

ショートが怖いのでラズパイのケースは発注しました・・・。リビングの電話台という、排熱できない環境に置くので耐久テストも兼ねてます。昔は同じ場所にThinkPad x41を置いてCentOSをインストールしてNASにしていましたが、夏場に40度にもなる環境で何年もトラブルなく動いていました。恐るべし昔のThinkPad。

最低限のセキュリティー

もちろん、デフォルトのラズパイはユーザpiとパスワードraspberryという公然のお約束があるので、セキュリティーユルユルです。

とりあえず自分がやった作業を書いておくと、まず次のように自分のアカウントを作り、piユーザを消しました。

$ sudo useradd ueda
###/etc/gropuのpiユーザを全部uedaに置換###
$ sudo userdel pi
$ sudo reboot

そして、鍵を仕込んだらパスワードで入れないようにしておきました。今回のネタは鍵認証を使いこなせない人はちと難しいので先にそちらをお勉強願います。

$ vi /etc/ssh/sshd_config 
###以下のように変更###
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no
###説明が面倒くさいのでreboot###
$ sudo reboot

で、ルータのグローバルIPとポート番号をラズパイのローカルIPとポート番号と結びつけて転送できるようにします。これは・・・ルータ依存なので説明しませんが、難しいですよね・・・。

設定ができたらルータのグローバルIPを調べて、外からラズパイに向かってsshできるか試しました。

グローバルIPを調べて某所に転送するスクリプトを書いてcronに登録

で、DDNSが使えないのでこれからどうするかというところですが、とりあえずラズパイから一定時間間隔でグローバルIPを別のインターネット上のサーバ(自分のVPS)に飛ばします。

ルータの持っているグローバルIPをどう調べるかわからなかったので、グーグルで調べたらすっきりしたQiitaのエントリーが見つかったので、その通りにしました。

ueda@raspberrypi ~ $ curl inet-ip.info
203.0.113.1

おお。

ということで、次のようなシェルスクリプトを書きました。必須の行は最終行だけで、curlでIPアドレスを調べ、test.example.comに飛ばし、test.example.com側の/tmp/homeipに保存するというワンライナーです。シェルスクリプトですが、シェル芸っぽいです。宣伝ですが、こういう小技がたくさん書いてあるシェルプログラミング実用テクニック (Software Design plus)(アフィ)もよろしくお願いいたします(最近、宣伝が少なくて出版社に報いてないので宣伝)。

ueda@raspberrypi ~ $ cat ~/SYS/SENDIP 
#!/bin/bash -vx

exec 2> /tmp/SENDIP.log

curl inet-ip.info | ssh test.example.com 'cat - > /tmp/homeip'

で、これをcrontabにしかけます。

ueda@raspberrypi ~ $ crontab -e
###以下のように1行書く###
*/10 * * * * /home/ueda/SYS/SENDIP

で、test.example.comに入って、10分後に更新されているか確認します。

ueda@test:~$ cat /tmp/homeip 
203.0.113.1

更新されていなかったら、ラズパイの/tmp/SENDIP.logにログが残っているので、バグがないか確認します。当然、鍵は通してある必要があり、また、(回避の方法を知らなければ)1度だけ最初に手でログインしておく必要があります。

自分のPCの設定

(追記: Windowsガン無視すいません・・・)
まず、.ssh/configに次のように書いておきます。IPアドレスはダミーです。

Host home
    HostName 127.0.0.1

で、次のようなシェルスクリプトを書きます。sshでtext.example.comにある/tmp/homeipのIPアドレスを読み込んで、sedで.ssh/configを上書きするという乱暴なものです。

uedamb:~ ueda$ cat ~/SYS/HOMEIP 
#!/bin/bash -xv

IP=$(ssh test.example.com 'cat /tmp/homeip')

sed -i.bak "/Host home/,/HostName/s/    HostName.*/    HostName $IP/" ~/.ssh/config

なかなか一発でバグなくsedの文を書くのは大変ですが、うまくいったら、.ssh/configが次のように書き換わります。

Host home
    HostName 203.0.113.1

このシェルスクリプトもcronに仕掛けても良いですが、多分そんなにIPアドレスは変わらないので手動で良いでしょう。

これで自宅にssh接続できるはずです。この作業は自宅でやったので、iPhoneのテザリングに変えてやってみました。

uedamb:~ ueda$ ssh home

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Dec 13 12:07:41 2015 from 192.168.0.2
ueda@raspberrypi ~ $ 

できました。

終わりに

サーバをセットしてから通信できるまで1時間くらいですが、手順を書くと結構いろんな小技が必要かなと思いました。別にwebサーバを立てているわけでもないのにDDNSを使っている人は、腕試しに試していただければと。

あと、ハマる点は、外づけHDDの電源がつくタイミングとラズパイが立ち上がるタイミングによってはマウントで止まってしまうので、fstabに情報を書くのはちと危険かもしれません。

とりあえずうまくいってよかった。寝る。

Pocket
LINEで送る