LoginSignup
8
11

More than 5 years have passed since last update.

コンピュータ将棋ソフトとの対局サーバーを立てよう<その1>

Last updated at Posted at 2017-03-03

1時間前まで コンピュータ囲碁やってた気もするんだが、コンピュータ将棋ソフトに切り替えよう。

要件定義

  • URL叩いたら指し手を返してほしい。1秒以内で。
  • 環境
    • レンタルサーバーは用意される
    • Linux

なるほど……、最近どんな騒ぎがあったのか知らないのかツッコミたいところだが わたしには関係ない。

思いついてみよう

まず わたしの環境なんだが

  • Windows 10

ぱっと思いつくところでは

  • 浮かむ瀬
  • Ubuntu ※第4回電王トーナメントでも大人気だ。USBに入れて突きさしてセットアップされる。
    • (追記)(初期インストール済み) 14.04.5 LTS (GNU/Linux 3.13.0-63-generic x86_64)
  • GCC g++-4.8以上
  • teratarm PuTTY
  • (追記) mono ※将棋所を使う場合
  • (追記) FileZilla
  • (追記)(初期インストール済み) nano ※テキストエディター
  • (追記)(初期インストール済み) bash ※シェル・スクリプト

だが Webサーバー を立てないといけない気もする。

  • Apache
  • PHP

があればいいんだろうか? 将棋ソフトって マルチユーザーに対応しているのか?キューとか要るんじゃないか?とりあえず1人用でいいか。

ローカル環境でテストもしたいし、Windows上でLinux を動かすバーチャルなあれなんて名前だったか……。思い出せないや、ググって出てくる バーチャルボックスを調べておこう。

テスト環境を作ろう

まず ローカルに テスト環境を構築しよう。

あとで記事を続ける。

Windows 10 で Virtual Box を導入できるだろうか。ググって読んでおこう。

参照 : 「WindowsでVirtualBoxを使用してLinux(Ubuntu)を動作させる手順と設定」 (俺の開発研究所) http://itmemo.net-luck.com/virtualbox-ubuntu/

とりあえず 浮かむ瀬 のソースはダウンロードしておこう。

参照 : 「第4回将棋電王トーナメント version (for Windows 64bit) (出場ソフト名「浮かむ瀬」)」 (Apery

open source shogi engine) http://hiraokatakuya.github.io/apery/

BIOSが起動しないぜ

Antec の CORE i3 なんだが、[F2][F10][F12][F8][Del] で BIOS が出てこなかった。
USBポートを左上の方に挿してみて [Del][F6] もやってみたが BIOS は出てこなかった。

もうちょっと調べてみる。

ローカルテスト環境 構築できなかったぜ。

無ければ無いで……。

そういえば、自宅の開発PCのBIOS 今まで見たことないな。

用意された さくらVPS 物理サーバー1台 の 2週間無料 ページを見る。
http://vps.sakura.ad.jp/

標準OSが「Ubuntu14.04 amd64 / Ubuntu16.04 amd64」か。じゃあもう Ubuntu インストールされてるや。

コンピューターとセキュリティ

ざっくり言って、コンピューターと言うのは 無制限に使うことより 制限して使う方に 発展している。
それもこれも 人類はガイア理論のような超個体ではなく、群集生物で1個体が利己的にリソースを使うからだが……。

で、コンピューターのリソースを使う人は ユーザー・アカウント を開設する。直訳すると口座でこの日本語はお金の出入り口の場所ぐらいの意味で分かりやすいんだが、account も何か count という語が入ってるし、接頭辞 ac- って何かと調べると「~の方へ」ぐらいの意味のようだ。

ユーザー・アカウントはもう用意されていた。
掴みどころとしては

  • ネットワーク上の住所 (IPアドレス)
  • その住所にあるコンピュータ内で使われる自分の氏名 (ユーザー名)
  • 本人確認をするもの (パスワード)

3つを聞いて控えておくと、コンピューターに入る(ログイン)こともできるし、ファイル(データ)を送ることもできる。
家に入って 送った荷物が届くようなものだ。

そういえば ログ というのは足跡のようなもので、いつコンピューター(家)に入ったかとか、コンピューターに入って何をしたかとか、最後にファイルを開いたのは誰か、とか残されていくんだが、コンピューターに入ることを ログイン と呼ぶのも興味深い。

そういえばルート・ユーザーというのがあったな

Teratarm という寺さんが作ったターミナルでログインしようかと思ったんだが、(へぇ、今はコミュニティが開発を後継しているのか)
開発PCのランチャーに PuTTY のアイコンがあったので PuTTY で接続してしまった。

接続プロトコルのタイプは SSH だ。なんかセキュリティーが高いんだろうぐらいしか分からないが「SSHだ」と言われたら SSH を選ぶしかない。こっちが好きなものを選べます、というやつじゃない。

PuTTYがなんかセキュリティ警告を出しているが気にせず [はい(Y)] を選んで入る。

ユーザー名に root と入れてパスワード叩いて Linux に入れね、とか思ってたんだが 聞いてみると ルート・ユーザーでは入れないらしい。
そういえばなんか su コマンドとかあった気もする。Windows 10 だって 自分のアカウントで入ってから右クリックして「管理者権限で実行」を選んだりもする。

なんかもう就活で Linuxの実務経験があります というのは止めておこう。ぜんぜんダメだ。

コマンドラインだ

ls ぐらいしか覚えてないんだが ぶーたれていると

sudo su -

というコマンドを教えてくれたので使ってみる。
パスワードを聞かれるので入れる。

とりあえず root ユーザーになったんじゃないか。これで 権限 というのが大きくなったので、何か役立つだろう。

ls

と叩く。何にも出ねー。

ls -an

と叩く。

. で始まる名前のファイルがいっぱい出てくる。隠しファイルばっかりか。
フォルダーや、隠しじゃないファイルは無いようだ。

mkdir shogi

とか適当にフォルダーを切ってみる。

ls -an

shogi フォルダー無ぇ~。

ここは どこなんだ。

cd ../

うわ、どこにいたのか分からなくなった。 home フォルダーにいたのかと思ったんだがなんかおかしい。root フォルダーにいたんじゃないか?

cd root
ls

ふむ……。 shogi フォルダーがあるな。
こんな root とかいう分けわかんないとこにフォルダーは要らないや。消しとこ……。

rmdir shogi/
ls

よし。

将棋ソフトはどこに デプロイメント(すぐ使えるように用意しておくこと。引っ越しでダンボール箱を引っ越し先に届けて箱を開けるところまで全部やろうという気分に似ている)すればいいんだ?

「各ディレクトリの役割を知ろう(ルートディレクトリ編) (1/2)」 (@ IT)
http://www.atmarkit.co.jp/ait/articles/0108/07/news002.html

bin に入れるにしては 将棋ソフトはコマンドな気はしない。なんか機能が巨大な気もするし、
root フォルダーなんか外からバンバン利用されるものを置いてていいのか分からんし、
lib というには 共有するソフトという気分でもない。
じゃあ etc か。設定ファイルじゃないし……。

じゃあ無難に home へ。

home ディレクトリの下に 自分のアカウント名のフォルダーがあるのでさらにその下へ。

パーミッション

ファイルの転送に失敗した、ぶーたれていると教えてくれた。そうだ Linux にはパーミッションがあったんだ!

ls -an
drwxr-xr-x ~略~ 01:37 shogi

パーミッション(ファイルの利用許可範囲の設定)は d:ディレクトリ の rwx、r-x、r-xで、
r:読取、w:書込、x:実行、-:権限なし という権限で、3つ並んでるんだが何だったか。

「第2回 「パーミッションの意味と使い分け」」 (MdN Design Interactive)
http://www.mdn.co.jp/di/articles/2104/?page=2

「所有者」「グループ」「その他」の3つが並んでるらしい。グループなんて使ったことないな。
うーむ、外からファイルを転送してこようと思ったら「その他」に書き込み権限 w を付けた方がいいんだろうか?

chmod 757 shogi/
ls -an
drwxr-xrwx ~略~ 01:37 shogi
        ~
        ここが変わった

はい、おっけ。

ファイルを転送しよう

FileZilla を使って Windows 10 から Linux へ Apery を転送しよう。

あれ? 日本語の抽象度がおかしいぜ。もう一度。

ファイル転送ソフトを使って Windows から Linux へコンピュータ将棋ソフトを転送しよう。

よし。
具体的には、

FileZilla を使って Windows 10 から Ubuntu へ 浮かむ瀬 を転送する。

よし。
なんか この日本語の抽象性と具体性の使い分けができないと、会話をしている相手が ファミコンのスーパーマリオが谷間に転落したあとに 飛び出してきたときのような 反応をすることがある。

もちろん わたしには そんな会話力なんか無いぜ。

あ、そうそう。サーバーからログアウトしよう。

exit
logout

なんか2回打たないとダメだった。
(※2017-03-06 追記: サーバーからexitして、PuTTYからexitしているようだ。コマンドは exit 2連打でOK)

ここで 用事でおでかけだ。帰ってから記事を続ける。

続き。

ログイン後の画面を見ると

Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-63-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
New release '16.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

と書いてある。

do-release-upgrade

と打ち込んだらいいのだろうか。
なんかパスワードを尋ねられたり、[yN] の入力を促されたりする。

なんか ポートを '1022' にしろ、みたいに書いてるけど無視して進める。

更新には several hour かかる、とか書いてある……、だったら お出かけ前に更新しておけばよかった……。

と思ったら [yN] をよく尋ねられるし PCから離れられない。
そして system will be restarted. という文字を見かけるが システムが再起動される様子もない。
どうもタイムアウトして接続が切れたらしい。

接続しなおすと メッセージが変わっていた。

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Sat Mar  4 20:59:46 2017 from ~略~
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

じゃあ 更新は終わったのだろうか。

sudo su -

でパスワード入力して rootユーザーに切り替える。

cd ../
ls
cd home
ls
cd アカウント名
ls
cd shogi
ls
apery-SDT4.tar.gz  apery-SDT4.zip

ふむ。どっちかがソースで、どっちかがバイナリだ。

どっちもソースじゃないか? よくわからん。

tar.gz の方を解凍できないだろうか。

unzip コマンドはインストールされてないか、パスが通ってないみたいなので、

apt install unzip

コマンドを試してみる。今度は unzip コマンドを叩けるようだ。

End-of-central-directory ~略~

と何かエラーらしきメッセージが返ってきている。じゃあ .zip の方を unzip してみる。
何か動いているようだ。

ls
apery-SDT4 ~以下略~

apery-SDT4 ディレクトリーが作られたのか。

cd apery-SDT4
ls
bin  Copying.txt  Readme.txt  src  utils

多分、ソースが展開されたのではないか。このソースをコンパイルできないか。

g++4.8以上というのが何なのか調べてみよう。

g++

「g++」(C++)
http://kaworu.jpn.org/cpp/g++

ややこしい名前だ……。

まず ubuntu に g++ が入っているか検索する。
上記Webサイトから

apt-cache search g++

をマウスのドラッグでコピーして、PuTTY へ右クリックで貼り付け。
なんか文字がいっぱい出力されて流れていった。なんなのかわからない。

「g++をUbuntuへインストールする」 (C++)
http://kaworu.jpn.org/cpp/g++%E3%82%92Ubuntu%E3%81%B8%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B

一番新しいバージョンに飛びつくぜ。

sudo apt install g++-4.9

インストールは終わったのだろうか。コマンドを打ってみる。

g++ --version

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

もう g++ はインストールできたんじゃないか。

apery のソースコードをコンパイルしよう

C言語はコンパイルの手続きを Makefile に書くと思うんだが g++ はどうか。

「Makefileの書き方」 (Web就活日記)
http://yut.hatenablog.com/entry/20120702/1341185909

浮かむ瀬 の Makefile は apery-SDT4/src/Makefile にあるようだ。

cd apery-SDT4/src/

Makefile のあるディレクトリまで カレントを移動。

gmake

No command 'gmake' found, did you mean:
~略~

違うのか……。

man -k g++

コマンドが多すぎて分からん。

「自動化のためのGNU Make入門講座 - Makefileの基本:ルール
Document 」 (オブラブ)
http://objectclub.jp/community/memorial/homepage3.nifty.com/masarl/article/gnu-make/rule.html

make

なんか動き出した。
出力の一部分を見てみると、

g++ -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../o
bj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.
o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/h
and.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/t
hread.o ../obj/common.o ../obj/pieceScore.o -lpthread  -std=c++11 -fno-exception
s -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp

と書いているので、ディレクトリを1つ上がったところの obj ディレクトリに 中間ファイル(.o)はできているのだろう。ところで Linux って .exe ファイルの代わりに何ができるのか? コマンド?

黄緑色の apery

うん?

ls
apery           evaluate.cpp       move.hpp                   search.hpp
benchmark.cpp   evaluate.hpp       movePicker.cpp             square.cpp
benchmark.hpp   generateMoves.cpp  movePicker.hpp             square.hpp
benchmark.sfen  generateMoves.hpp  mt64bit.cpp                thread.cpp
bitboard.cpp    hand.cpp           mt64bit.hpp                thread.hpp
bitboard.hpp    hand.hpp           overloadEnumOperators.hpp  timeManager.cpp
book.cpp        ifdef.hpp          piece.hpp                  timeManager.hpp
book.hpp        init.cpp           pieceScore.cpp             tt.cpp
color.hpp       init.hpp           pieceScore.hpp             tt.hpp
common.cpp      learner.hpp        position.cpp               usi.cpp
common.hpp      main.cpp           position.hpp               usi.hpp
evalList.cpp    Makefile           score.hpp
evalList.hpp    move.cpp           search.cpp

リストの先頭にある apery、あれ、フォルダーじゃなくて 実行ファイルなんじゃないか?

ls -an
-rwxr-xr-x 1 0 0 444728 Mar  4 22:16 apery

パーミッションに x が付いている。実行できるんじゃないか?

apery
apery: command not found

何がダメなのか……。

「lsっぽいコマンドを作る」 (碧色工房)
http://www.mm2d.net/main/prog/linux/ls-08.html

実行可能なファイルなんじゃないのか……。

「ubuntu初心者です。 端末でプログラムの実行を」 (YAHOO!JAPAN知恵袋)
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1356985753

./apery

おっ、なんか処理が返ってこずにブロックされたぜ。バックグラウンドで動かせばいいんじゃないか?

プログラムを強制終了させよう

[Ctrl] + [C] でも押しとけば止まるんじゃないか。止まった。

プログラムをバックグラウンドで実行させよう

じゃあ、バックグラウンドで実行するには。

「【Linux】ジョブのバックグラウンド実行」 (Qiita)
http://qiita.com/fujitetsu/items/665413e0dc8b0cc3b6ed

QiitaからQiitaへの記事ぐらい なんか WordPress みたいに かっこいいリンクに差し替えてくれたらいいのにwwwww
コマンドの末尾に & を付けるといいらしい。

./apery &
[1] 1692

ほう。

Aperyに標準入力で入力しよう

じゃあ、apery に話しかけれるのだろうか? 牛とか。

「図解:標準入力、標準出力、標準エラー出力、パイプとは ?」 (Linux)
http://www.creatology.jp/unix/outin.html

echo 'usi' > ./apery
-su: ./apery: Text file busy

違うのか。

「(2−5)複数のコマンド間で標準入出力を共有し,連携するためには,パイプを用いる。」 (Linux上でシェルが実行される仕組みを,体系的に理解しよう (bash 中級者への道))
http://language-and-engineering.hatenablog.jp/entry/20110617/p1

じゃあ パイプ(縦棒)でつないでみよう。

echo 'usi' | ./apery
id name Apery Debug Build
id author Hiraoka Takuya

option name Best_Book_Move type check default false
option name Book_File type string default book/20150503/book.bin
option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
option name Clear_Hash type button
option name Draw_Ply type spin default 256 min 1 max 2147483647
option name Engine_Name type string default Apery Debug Build
option name Max_Book_Ply type spin default 32767 min 0 max 32767
option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Score type spin default -180 min -32601 max 32601
option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
option name Move_Overhead type spin default 30 min 0 max 5000
option name MultiPV type spin default 1 min 1 max 594
option name OwnBook type check default true
option name Slow_Mover type spin default 89 min 1 max 1000
option name Slow_Mover_10 type spin default 10 min 1 max 1000
option name Slow_Mover_16 type spin default 20 min 1 max 1000
option name Slow_Mover_20 type spin default 40 min 1 max 1000
option name Threads type spin default 2 min 1 max 256
option name Time_Margin type spin default 4500 min 0 max 2147483647
option name USI_Hash type spin default 256 min 1 max 1048576
option name USI_Ponder type check default true
usiok

おっ! Apery と会話でけたな!

デバッグ・ビルド と リリース・ビルド

だが ちょっと待ってほしい。

id name Apery Debug Build

とても気になるぜ。これって、デバッグ・モードでコンパイルしたエイプリーなんじゃないか?
デバッグ・モードでない方法でコンパイルしてくれる方法を調べよう……。

apery-SDT4 の usi.cpp を見ると、

#ifdef NDEBUG
    (*this)["Engine_Name"]                 = USIOption("ukamuse_SDT4");
#else
    (*this)["Engine_Name"]                 = USIOption("Apery Debug Build");
#endif

と書いている。 NDEBUG というプリプロセッサ・マクロ を make に指定できれば ukamuse_SDT4 君になってくれると思うんだが……。
Makefile ファイルには

-DNDEBUG

という記述を よく見かける。 -D と NDEBUG なのだろう。どうやって利用するのか?

「Makefileの書き方」 (Web就活日記)
http://yut.hatenablog.com/entry/20120702/1341185909

じゃあ、こうか。

make bmi2
make CFLAGS='-std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopen
mp -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -ma
vx2' LDFLAGS='-lpthread  -flto' apery
make[1]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
make[1]: 'apery' is up to date.
make[1]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'

うーむ。何が起こったのか。

バックグラウンドのプロセスを止めよう

そういえば Apery Debug Build 君をバックグラウンドで起動しっぱなしだったな。

「【 stop 】 バックグラウンドのジョブを停止する」 (ITPro)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230891/

%1692
-su: fg: %1692: no such job

あらー。

jobs
[1]+  Stopped                 ./apery

いつのまに止まっていたのか。

ファイルを削除してもう一回 make すると?

rm apery
ls

よし。

make bmi2
make CFLAGS='-std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopen
mp -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -ma
vx2' LDFLAGS='-lpthread  -flto' apery
make[1]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
g++ -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../o
bj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.
o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/h
and.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/t
hread.o ../obj/common.o ../obj/pieceScore.o -lpthread  -flto -std=c++11 -fno-exc
eptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -DNDEBUG -DHAVE_SSE4 -DHAVE_S
SE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2
make[1]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'

ls

よし。作り直した。

echo 'usi' | ./apery
id name Apery Debug Build

ダメじゃないかwwww

make publish
~中略~
echo 'usi' | ./apery
id name ukamuse_SDT4

これなら いけるのか。しかしベンチマークが走り出して時間がかかりすぎる。あるいは 最適化のために、わざと走らせているのか。

クリーンしよう

2回目の make publish をしようとしたら

Illegal instruction

とか言われて止まってしまう。

make clean

とでもすればいいのか?

cd ..
ls obj

objディレクトリの中を空っぽにしてくれたみたいだ。

make publish

よし、またコンパイルが走り出した。

イリーガル インストラクション

./apery
Illegal instruction

うまくいかないものだ。

apery を bin フォルダーに移動するとどうだろうか?

mv apery ../bin/apery
ls
ls ../bin
apery

よし。

../bin/apery
Illegal instruction

どこか壊してしまったのか、評価ファイルが無いかなのだろうか?

Makefile と make publish

うん? Makefile に何か書いてるぞ。

#CFLAGS   += -march=native # make publish の時はここをコメントアウトする必要がある。

コメントアウトしてるよなあ。頭に # が付いてるし。

make publish
make profgen
make[1]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
make CFLAGS='-std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov' LDFLAGS='-lpthread  -fprofile-generate -lgcov' bmi2
make[2]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
make CFLAGS='-std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2' LDFLAGS='-lpthread  -fprofile-generate -lgcov -flto' apery
make[3]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/main.o -c main.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/bitboard.o -c bitboard.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/init.o -c init.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/mt64bit.o -c mt64bit.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/position.o -c position.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/evalList.o -c evalList.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/move.o -c move.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/movePicker.o -c movePicker.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/square.o -c square.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/usi.o -c usi.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/generateMoves.o -c generateMoves.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/evaluate.o -c evaluate.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/search.o -c search.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/hand.o -c hand.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/tt.o -c tt.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/timeManager.o -c timeManager.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/book.o -c book.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/benchmark.o -c benchmark.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/thread.o -c thread.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/common.o -c common.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2  -o ../obj/pieceScore.o -c pieceScore.cpp
g++ -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../obj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/hand.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/thread.o ../obj/common.o ../obj/pieceScore.o -lpthread  -fprofile-generate -lgcov -flto -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE4 -DHAVE_SSE42 -DHAVE_BMI2 -msse4.2 -mbmi2 -DHAVE_AVX2 -mavx2
make[3]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'
make[2]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'
make[1]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'
Makefile:86: recipe for target 'publish' failed
make: *** [publish] Illegal instruction

じゃあ、

make clean
make profgen_sse

こんどはコンパイルできたか?

ls
~略~
echo 'usi' | ./apery
id name ukamuse_SDT4
id author Hiraoka Takuya

option name Best_Book_Move type check default false
option name Book_File type string default book/20150503/book.bin
option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
option name Clear_Hash type button
option name Draw_Ply type spin default 256 min 1 max 2147483647
option name Engine_Name type string default ukamuse_SDT4
option name Max_Book_Ply type spin default 32767 min 0 max 32767
option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Score type spin default -180 min -32601 max 32601
option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
option name Move_Overhead type spin default 30 min 0 max 5000
option name MultiPV type spin default 1 min 1 max 594
option name OwnBook type check default true
option name Slow_Mover type spin default 89 min 1 max 1000
option name Slow_Mover_10 type spin default 10 min 1 max 1000
option name Slow_Mover_16 type spin default 20 min 1 max 1000
option name Slow_Mover_20 type spin default 40 min 1 max 1000
option name Threads type spin default 2 min 1 max 256
option name Time_Margin type spin default 4500 min 0 max 2147483647
option name USI_Hash type spin default 256 min 1 max 1048576
option name USI_Ponder type check default true
usiok

よし!

ベンチマークを取ってみよう

./apery &
[3] 2508

どうも このとき、私はコピペをしようとして [Ctrl] + [C] を押していて、プロセスを落としている気がする。
やりなおし。

./apery &
[4] 2511

PuTTYでは、マウスドラッグでなぞるだけで コピーはできるのだ。
左ボタンクリックで貼り付け。

echo 'bench' | ./apery

[4]+  Stopped                 ./apery

うーむ、こういう使い方じゃないのか?

./apery bench
Killed

これも違う。

ソースコードを読んでいるんだが、そういや、きふわらぷりーを作っているとき、.exe と一緒のフォルダーに benchmark.sfen ファイルが無かったら落ちてたなあ。

ls
apery           evaluate.cpp       move.hpp                   search.hpp
benchmark.cpp   evaluate.hpp       movePicker.cpp             square.cpp
benchmark.hpp   generateMoves.cpp  movePicker.hpp             square.hpp
benchmark.sfen  generateMoves.hpp  mt64bit.cpp                thread.cpp
bitboard.cpp    hand.cpp           mt64bit.hpp                thread.hpp
bitboard.hpp    hand.hpp           overloadEnumOperators.hpp  timeManager.cpp
book.cpp        ifdef.hpp          piece.hpp                  timeManager.hpp
book.hpp        init.cpp           pieceScore.cpp             tt.cpp
color.hpp       init.hpp           pieceScore.hpp             tt.hpp
common.cpp      learner.hpp        position.cpp               usi.cpp
common.hpp      main.cpp           position.hpp               usi.hpp
evalList.cpp    Makefile           score.hpp
evalList.hpp    move.cpp           search.cpp

ある。じゃあ、apery と benchmark.sfen を bin フォルダーに持っていけばいいのだろうか?

mv apery ../bin/apery
mv benchmark.sfen ../bin/benchmark.sfen
ls ../bin
apery  benchmark.sfen

これでどうか?

../bin/apery bench
Killed

だめなのか。

../bin/apery bench &
[5] 2571
[1]   Stopped                 ./apery
[2]   Stopped                 ./apery
[3]-  Stopped                 ./apery
[4]+  Stopped                 ./apery
[5]   Killed                  ../bin/apery bench

Killed と Stopped の違いはなんだろうか。

きふわらぷりーで bench

大樹の枝を改悪した きふわらぷりー だと、まず Kifuwarapery.exe をダブルクリックしてコマンドプロンプトを出し、
しばらく待って入力できる状態になってから bench と入力して[Enter]キーを押すとベンチマークが走り出す。

浮かむ瀬も同じかと思うんだが……。

./apery

のあと、すぐ Killed になっているんじゃないだろうか?

aperyのmain.cppにあるmain関数は

// 将棋を指すソフト
int main(int argc, char* argv[]) {
    initTable();
    Position::initZobrist();
    HuffmanCodedPos::init();
    auto s = std::unique_ptr<Searcher>(new Searcher);
    s->init();
    s->doUSICommandLoop(argc, argv);
    s->threads.exit();
}

なので、 コマンド・ループで止まっていてくれると思うんだが……、調べてみるか。

void Searcher::doUSICommandLoop(int argc, char* argv[]) {
    bool evalTableIsRead = false;
    Position pos(DefaultStartPositionSFEN, threads.main(), thisptr);

    std::string cmd;
    std::string token;

    for (int i = 1; i < argc; ++i)
        cmd += std::string(argv[i]) + " ";

    do {
        if (argc == 1 && !std::getline(std::cin, cmd))
            cmd = "quit";

        std::istringstream ssCmd(cmd);

        ssCmd >> std::skipws >> token;

        if (token == "quit" || token == "stop" || token == "ponderhit" || token == "gameover") {
            if (token != "ponderhit" || signals.stopOnPonderHit) {
                signals.stop = true;
                threads.main()->startSearching(true);
            }
            else
                limits.ponder = false;
            if (token == "ponderhit" && limits.moveTime != 0)
                limits.moveTime += timeManager.elapsed();
        }
        else if (token == "go"       ) go(pos, ssCmd);
        else if (token == "position" ) setPosition(pos, ssCmd);
        else if (token == "usinewgame"); // isready で準備は出来たので、対局開始時に特にする事はない。
        else if (token == "usi"      ) SYNCCOUT << "id name " << std::string(options["Engine_Name"])
                                                << "\nid author Hiraoka Takuya"
                                                << "\n" << options
                                                << "\nusiok" << SYNCENDL;
        else if (token == "isready"  ) { // 対局開始前の準備。
            tt.clear();
            threads.main()->previousScore = ScoreInfinite;
            if (!evalTableIsRead) {
                // 一時オブジェクトを生成して Evaluator::init() を呼んだ直後にオブジェクトを破棄する。
                // 評価関数の次元下げをしたデータを格納する分のメモリが無駄な為、
                std::unique_ptr<Evaluator>(new Evaluator)->init(Evaluator::evalDir, true);
                evalTableIsRead = true;
            }
            SYNCCOUT << "readyok" << SYNCENDL;
        }
        else if (token == "setoption") setOption(ssCmd);
        else if (token == "write_eval") { // 対局で使う為の評価関数バイナリをファイルに書き出す。
            if (!evalTableIsRead)
                std::unique_ptr<Evaluator>(new Evaluator)->init(Evaluator::evalDir, true);
            Evaluator::writeSynthesized(Evaluator::evalDir);
        }
#if defined LEARN
        else if (token == "l"        ) {
            auto learner = std::unique_ptr<Learner>(new Learner);
            learner->learn(pos, ssCmd);
        }
        else if (token == "make_teacher") {
            if (!evalTableIsRead) {
                std::unique_ptr<Evaluator>(new Evaluator)->init(Evaluator::evalDir, true);
                evalTableIsRead = true;
            }
            make_teacher(ssCmd);
        }
        else if (token == "use_teacher") {
            if (!evalTableIsRead) {
                std::unique_ptr<Evaluator>(new Evaluator)->init(Evaluator::evalDir, true);
                evalTableIsRead = true;
            }
            use_teacher(pos, ssCmd);
        }
        else if (token == "check_teacher") {
            check_teacher(ssCmd);
        }
        else if (token == "print"    ) printEvalTable(SQ88, f_gold + SQ78, f_gold, false);
#endif
#if !defined MINIMUL
        // 以下、デバッグ用
        else if (token == "bench"    ) {
            if (!evalTableIsRead) {
                std::unique_ptr<Evaluator>(new Evaluator)->init(Evaluator::evalDir, true);
                evalTableIsRead = true;
            }
            benchmark(pos);
        }
        else if (token == "key"      ) SYNCCOUT << pos.getKey() << SYNCENDL;
        else if (token == "tosfen"   ) SYNCCOUT << pos.toSFEN() << SYNCENDL;
        else if (token == "eval"     ) std::cout << evaluateUnUseDiff(pos) / FVScale << std::endl;
        else if (token == "d"        ) pos.print();
        else if (token == "s"        ) measureGenerateMoves(pos);
        else if (token == "t"        ) std::cout << pos.mateMoveIn1Ply().toCSA() << std::endl;
        else if (token == "b"        ) makeBook(pos, ssCmd);
#endif
        else                           SYNCCOUT << "unknown command: " << cmd << SYNCENDL;
    } while (token != "quit" && argc == 1);

    threads.main()->waitForSearchFinished();
}

うーむ。Windowsの実行と、Linuxの実行に違いはあるのだろうか。

Makefile:86: recipe for target 'publish' failed
make: *** [publish] Killed

うーむ。よく Killed が出てくるようになった。

jobs
[1]   Stopped                 ./apery
[2]   Stopped                 ./apery
[3]   Stopped                 ./apery
[4]   Stopped                 ./apery
[5]-  Stopped                 ./apery  (wd: /home/csg10/shogi/apery-SDT4/bin)
[6]+  Stopped                 ./apery  (wd: /home/csg10/shogi/apery-SDT4/bin)

この Stopped が溜まっているのはいいのだろうか?

killコマンドを使ってみよう

「バックグラウンドプロセス(ジョブ)の管理Add Star」 (satake7’s memo)
http://d.hatena.ne.jp/satake7/20080606/p1

こうだろうか。

kill %1
jobs
[1]   Terminated              ./apery
[2]   Stopped                 ./apery
[3]   Stopped                 ./apery
[4]   Stopped                 ./apery
[5]-  Stopped                 ./apery  (wd: /home/csg10/shogi/apery-SDT4/bin)
[6]+  Stopped                 ./apery  (wd: /home/csg10/shogi/apery-SDT4/bin)

Stopped が Terminated に変わったが、なんのこっちゃ。
この調子で全部のジョブをkillした。

jobs
make clean
make publish

だめか。

profgen_sse2

    make clean
    make profgen_sse2
make CFLAGS='-std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov' LDFLAGS='-lpthread  -fprofile-generate -lgcov' sse2
make[1]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
make CFLAGS='-std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2' LDFLAGS='-lpthread  -fprofile-generate -lgcov -flto' apery
make[2]: Entering directory '/home/csg10/shogi/apery-SDT4/src'
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/main.o -c main.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/bitboard.o -c bitboard.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/init.o -c init.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/mt64bit.o -c mt64bit.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/position.o -c position.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/evalList.o -c evalList.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/move.o -c move.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/movePicker.o -c movePicker.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/square.o -c square.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/usi.o -c usi.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/generateMoves.o -c generateMoves.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/evaluate.o -c evaluate.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/search.o -c search.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/hand.o -c hand.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/tt.o -c tt.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/timeManager.o -c timeManager.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/book.o -c book.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/benchmark.o -c benchmark.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/thread.o -c thread.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/common.o -c common.cpp
g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2  -o ../obj/pieceScore.o -c pieceScore.cpp
g++ -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../obj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/hand.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/thread.o ../obj/common.o ../obj/pieceScore.o -lpthread  -fprofile-generate -lgcov -flto -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -fprofile-generate -lgcov -DNDEBUG -DHAVE_SSE2 -msse2
make[2]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'
make[1]: Leaving directory '/home/csg10/shogi/apery-SDT4/src'

これは うまくいったんじゃないか?

./apery &
[1] 3144
jobs
[1]+  Stopped                 ./apery

だめか。

./apery bench
info string start setting eval table
info string end setting eval table

なんのこっちゃ。今までよりは 反応があるだけマシか。

どうも、メインループからすぐ抜けてしまうのか、Stopped になってしまうようだ。

評価関数ファイルが無いんじゃないか?

きふわらぷりーは どうやって動いてるのか 調べてみよう……。

評価ファイルを作る make_synthesized_eval.sh みたいなファイルを .bat に書き直して 20151105 フォルダーに KPP_synthesized.bin、KK_synthesized.bin、KKP_synthesized.bin の3つのバイナリを生成している。

調べよう。

ukamuse_sdt4.zip

ukamuse_sdt4.zip というバイナリもあるみたいだ。なんだこれ。FileZilla で Linuxサーバー へ転送して unzip してみよう。

unzip ukamuse_sdt4.zip

inflating:
とか
creating:
とか出てくるが何だろうか。

あら、ukamuse_sdt4 にも src が入っている。

ls
20161007  ukamuse_sdt4_bmi2.exe  ukamuse_sdt4_sse2.exe  ukamuse_sdt4_sse41.exe  ukamuse_sdt4_sse42.exe

そして .bin の中には exe も入っているが、Linux で使うのだろうか?

20161007 フォルダーの中には

ls
KKP_synthesized.bin  KPP_synthesized.bin  log_v1.10.0.txt  log_v1.1.1.txt   log_v1.13.0.txt  log_v1.2.0_2.txt  log_v1.3.0.txt  log_v1.5.0.txt  log_v1.7.0.txt
KK_synthesized.bin   log_v1.0.3.txt       log_v1.11.0.txt  log_v1.12.0.txt  log_v1.14.0.txt  log_v1.2.0.txt    log_v1.4.0.txt  log_v1.6.0.txt  log_v1.8.1.txt

と、いろいろ入っている。じゃあ ukamuse_sdt4 フォルダーの中で Linux用にコンパイルし直したらいいのだろうか?

じゃあ src ディレクトリーで

make publish
~中略~
Makefile:86: recipe for target 'publish' failed
make: *** [publish] Illegal instruction

なんか CPU が対応してないんじゃないか。

make clean
make profgen_sse2

これならコンパイルが通る。

mv apery ../bin/apery
ls
20161007  apery  ukamuse_sdt4_bmi2.exe  ukamuse_sdt4_sse2.exe  ukamuse_sdt4_sse41.exe  ukamuse_sdt4_sse42.exe

これでどうか。

./apery

よし、ループでブロック(ループを抜けない)されてる感じがする。[Ctrl]+[C]で抜ける。

./apery bench

数秒でループを抜けたようだ。よく分からない。

./apery

これでしばらく待つ。
なんも起こらない。

./apery &
[1] 3459
jobs
[1]+  Stopped                 ./apery

だめか。

src/evaluate.cpp ファイルには

std::string Evaluator::evalDir = "20161007";

と書いているので、フォルダー名は合っているのだろう。
じゃあ次は src ディレクトリで

cp benchmark.sfen ../bin/benchmark.sfen

を実行。

あっ、bench 動いた。

./apery bench

今度は bench が実行された。テスト用の局面に対して 読み筋がどんどん並んでいる。

info depth 16 seldepth 37 multipv 1 score cp -562 upperbound nodes 1866534 nps 206978 time 9018 pv 6g6h+ 5h4i 6h6g S*5b 3a4b 5b4c+ 4b4c 6f6e 6g5g 6e7d B*6g 4i3h 6g5f+ 7d6d 5g4g 3h2g 2b5e R*5a
info nodes 1950370 time 9518
bestmove 6g6h+ ponder 5h4i

じゃあ対局はどうか?

./apery usi &
[2] 3510
id name ukamuse_SDT4
id author Hiraoka Takuya

option name Best_Book_Move type check default false
option name Book_File type string default book/20150503/book.bin
option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
option name Clear_Hash type button
option name Draw_Ply type spin default 256 min 1 max 2147483647
option name Engine_Name type string default ukamuse_SDT4
option name Max_Book_Ply type spin default 32767 min 0 max 32767
option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Score type spin default -180 min -32601 max 32601
option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
option name Move_Overhead type spin default 30 min 0 max 5000
option name MultiPV type spin default 1 min 1 max 594
option name OwnBook type check default true
option name Slow_Mover type spin default 89 min 1 max 1000
option name Slow_Mover_10 type spin default 10 min 1 max 1000
option name Slow_Mover_16 type spin default 20 min 1 max 1000
option name Slow_Mover_20 type spin default 40 min 1 max 1000
option name Threads type spin default 2 min 1 max 256
option name Time_Margin type spin default 4500 min 0 max 2147483647
option name USI_Hash type spin default 256 min 1 max 1048576
option name USI_Ponder type check default true
usiok
jobs
[1]+  Stopped                 ./apery
[2]-  Done                    ./apery usi
 jobs
[1]+  Stopped                 ./apery

Done じゃないんだが……。常駐してほしいんだが……。

「○自作プログラムをデーモンとして起動させる」
http://7ujm.net/linux/daemon.html

将棋プログラムは デーモンなのか?

メインループに入っているのでは?

./apery
bench

のあと 右キーか何か押したら bench が走った。どういうことなのか。

bench と入れると bench が走るんだが、usi と入れても走らない。何が違うのか。

unknown command:       usi
eval
-243

eval はオッケーなのか。

print
unknown command: print

print はダメなのか。

key
4543979467506711947

key はオッケーなのか。

tosfen
sfen l5knl/7b1/p3pg1gp/1pr3Pp1/5pS2/1PpGP4/2gpBPS1P/4K2R1/LN5NL w 2Sn5p 74

tosfen はオッケーなのか。

d
'  9  8  7  6  5  4  3  2  1
P1-KY *  *  *  *  * -OU-KE-KY
P2 *  *  *  *  *  *  * -KA *
P3-FU *  *  * -FU-KI * -KI-FU
P4 * -FU-HI *  *  * +FU-FU *
P5 *  *  *  *  * -FU+GI *  *
P6 * +FU-FU+KI+FU *  *  *  *
P7 *  * -KI-FU+KA+FU+GI * +FU
P8 *  *  *  * +OU *  * +HI *
P9+KY+KE *  *  *  *  * +KE+KY
P+00GI00GI
P-00FU00FU00FU00FU00FU
P-00KE
-

key = 4543979467506711947

d もオッケーなのか。printはダメなのに。

s
'  9  8  7  6  5  4  3  2  1
P1-KY *  *  *  *  * -OU-KE-KY
P2 *  *  *  *  *  *  * -KA *
P3-FU *  *  * -FU-KI * -KI-FU
P4 * -FU-HI *  *  * +FU-FU *
P5 *  *  *  *  * -FU+GI *  *
P6 * +FU-FU+KI+FU *  *  *  *
P7 *  * -KI-FU+KA+FU+GI * +FU
P8 *  *  *  * +OU *  * +HI *
P9+KY+KE *  *  *  *  * +KE+KY
P+00GI00GI
P-00FU00FU00FU00FU00FU
P-00KE
-

key = 4543979467506711947
elapsed = 2870 [msec]
times/s = 1742160 [times/sec]
num of moves = 78
6768TO, 2266KA, 7434HI, 2334KI, 4334KI, 1314FU, 2425FU, 4546FU, 5354FU, 8485FU, 9394FU, 1112KY, 9192KY, 2133KE, 2233KA, 2244KA, 2255KA, 7444HI, 7454HI, 7464HI, 7471HI, 7472HI, 7473HI, 7475HI, 2314KI, 2333KI, 4333KI, 4342KI, 4344KI, 4354KI, 7768KI, 7778KI, 7787KI, 7788KI, 3132OU, 3141OU, 3142OU, 0032FU, 0033FU, 0036FU, 0038FU, 0012KE, 0014KE, 0015KE, 0016KE, 0025KE, 0026KE, 0027KE, 0032KE, 0033KE, 0036KE, 0041KE, 0042KE, 0044KE, 0046KE, 0051KE, 0052KE, 0054KE, 0055KE, 0061KE, 0062KE, 0063KE, 0064KE, 0065KE, 0071KE, 0072KE, 0073KE, 0075KE, 0081KE, 0082KE, 0083KE, 0085KE, 0087KE, 0092KE, 0094KE, 0095KE, 0096KE, 0097KE,

s もいける。

t
None

t もいける。

b
I cannot open

b もいける。

あーっ

#if defined LEARN

print は 学習用のコマンドか。

write_eval

あっ、時間かかりそう。 [Ctrl]+[C]。

setoption
No such option:

setoption もいけてそう。

isready
readyok

isready もいけてるじゃないか。

usi
id name ukamuse_SDT4
id author Hiraoka Takuya

option name Best_Book_Move type check default false
option name Book_File type string default book/20150503/book.bin
option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
option name Clear_Hash type button
option name Draw_Ply type spin default 256 min 1 max 2147483647
option name Engine_Name type string default ukamuse_SDT4
option name Max_Book_Ply type spin default 32767 min 0 max 32767
option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Score type spin default -180 min -32601 max 32601
option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
option name Move_Overhead type spin default 30 min 0 max 5000
option name MultiPV type spin default 1 min 1 max 594
option name OwnBook type check default true
option name Slow_Mover type spin default 89 min 1 max 1000
option name Slow_Mover_10 type spin default 10 min 1 max 1000
option name Slow_Mover_16 type spin default 20 min 1 max 1000
option name Slow_Mover_20 type spin default 40 min 1 max 1000
option name Threads type spin default 2 min 1 max 256
option name Time_Margin type spin default 4500 min 0 max 2147483647
option name USI_Hash type spin default 256 min 1 max 1048576
option name USI_Ponder type check default true
usiok

usi もいけてるじゃないか。

じゃあ、手動で対局できるか調べてみるか。もう一度最初から。

手動で対局しようぜ

私が打つ

./apery
usi

次、浮かむ瀬が返してくる。

id name ukamuse_SDT4
id author Hiraoka Takuya

option name Best_Book_Move type check default false
option name Book_File type string default book/20150503/book.bin
option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
option name Clear_Hash type button
option name Draw_Ply type spin default 256 min 1 max 2147483647
option name Engine_Name type string default ukamuse_SDT4
option name Max_Book_Ply type spin default 32767 min 0 max 32767
option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Score type spin default -180 min -32601 max 32601
option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
option name Move_Overhead type spin default 30 min 0 max 5000
option name MultiPV type spin default 1 min 1 max 594
option name OwnBook type check default true
option name Slow_Mover type spin default 89 min 1 max 1000
option name Slow_Mover_10 type spin default 10 min 1 max 1000
option name Slow_Mover_16 type spin default 20 min 1 max 1000
option name Slow_Mover_20 type spin default 40 min 1 max 1000
option name Threads type spin default 2 min 1 max 256
option name Time_Margin type spin default 4500 min 0 max 2147483647
option name USI_Hash type spin default 256 min 1 max 1048576
option name USI_Ponder type check default true
usiok

次、わたしが打つ。

usinewgame
position startpos moves
go

次、浮かむ瀬が返してくる。

info string optimum_time = 20
info string maximum_time = 20
info string book_ply 32767
info depth 1 seldepth 1 multipv 1 score cp 0 nodes 67 nps 1367 time 49 pv 1g1f
bestmove 1g1f

脳内で将棋盤をいじくる。1g1f というのは 1六歩 だが、なんで端歩を突くのか。
じゃあ 1四歩 としよう。

position sfen lnsgkgsnl/1b5r1/pppppppp1/8p/9/8P/PPPPPPPP1/1B5R1/LNSGKGSNL b - 1 moves 1g1f 1c1d
go

なんか 浮かむ瀬がノータイムで返してくる。

info string optimum_time = 20
info string maximum_time = 20
info string book_ply 32767
info depth 1 seldepth 1 multipv 1 score cp 0 nodes 72 nps 3272 time 22 pv 2g2f
info depth 2 seldepth 2 multipv 1 score cp 0 nodes 195 nps 4062 time 48 pv 2g2f 2c2d
bestmove 2g2f ponder 2c2d

なぜ ノータイムなのか。とりあえず 浮かむ瀬とは指せるようだ。
じゃあ終了しよ……。
私が打つ。

gameover
quit

あとは設定をいじろう。

設定を見てみよう

option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647

学習の用途とかで 0.02 秒で返すようにしてあるんだろうか。
コンピューターに1秒で指させるんなら、通信にかかる時間に3秒ぐらいとっておきたいが要件定義を満たさないので、0.5 秒ぐらい思考させるか。

setoption name Minimum_Thinking_Time value 500

これを usinewgame の前に思考エンジンに送ってやればいいんだろうか?

./apery
usi
id name ukamuse_SDT4
id author Hiraoka Takuya

option name Best_Book_Move type check default false
option name Book_File type string default book/20150503/book.bin
option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
option name Clear_Hash type button
option name Draw_Ply type spin default 256 min 1 max 2147483647
option name Engine_Name type string default ukamuse_SDT4
option name Max_Book_Ply type spin default 32767 min 0 max 32767
option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Ply type spin default 32767 min 0 max 32767
option name Min_Book_Score type spin default -180 min -32601 max 32601
option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
option name Move_Overhead type spin default 30 min 0 max 5000
option name MultiPV type spin default 1 min 1 max 594
option name OwnBook type check default true
option name Slow_Mover type spin default 89 min 1 max 1000
option name Slow_Mover_10 type spin default 10 min 1 max 1000
option name Slow_Mover_16 type spin default 20 min 1 max 1000
option name Slow_Mover_20 type spin default 40 min 1 max 1000
option name Threads type spin default 2 min 1 max 256
option name Time_Margin type spin default 4500 min 0 max 2147483647
option name USI_Hash type spin default 256 min 1 max 1048576
option name USI_Ponder type check default true
usiok
isready
readyok
setoption name Minimum_Thinking_Time value 500
usinewgame
position startpos moves
go
info string optimum_time = 500
info string maximum_time = 500
info string book_ply 32767
info depth 1 seldepth 1 multipv 1 score cp 63 nodes 64 nps 1230 time 52 pv 2g2f
info depth 2 seldepth 2 multipv 1 score cp 173 nodes 108 nps 1611 time 67 pv 2g2f 1c1d
info depth 3 seldepth 3 multipv 1 score cp 155 nodes 229 nps 2462 time 93 pv 2g2f 3c3d 2f2e
info depth 4 seldepth 4 multipv 1 score cp 291 nodes 341 nps 2772 time 123 pv 2g2f 3c3d 2f2e 1c1d 2e2d
info depth 5 seldepth 5 multipv 1 score cp 252 nodes 1781 nps 6720 time 265 pv 2g2f 8c8d 2f2e 8d8e 2e2d 2c2d 2h2d
info depth 6 seldepth 6 multipv 1 score cp 252 nodes 2047 nps 6603 time 310 pv 2g2f 8c8d 2f2e 8d8e 2e2d 2c2d 2h2d
info depth 7 seldepth 7 multipv 1 score cp 252 nodes 2653 nps 6615 time 401 pv 2g2f 8c8d 2f2e 8d8e 2e2d 2c2d 2h2d 8e8f
info depth 8 seldepth 9 multipv 1 score cp 22 nodes 6478 nps 6733 time 962 pv 2g2f 8c8d 2f2e 8d8e 6i7h 8e8f 8g8f 8b8f
bestmove 2g2f ponder 8c8d

うむ、0.5秒以上は考えているようだ、飛車先の歩を伸ばしているから 大丈夫そうだ。これだけ見ると……。

次はシェル・スクリプトか?

ループ待機している浮かむ瀬の、標準入力をシェル・スクリプトか何かに、標準出力を同じくシェル・スクリプトか何かにして、キャッチボールができればいいんだが、将棋所にできるんだし、やる方法はあるんだろう……。

あるいはそれこそ C++ でもいいのかもしれないが……、できれば PHP と連携したい。

どういう方法があるかは また今度考えよう。

打鍵で 浮かむ瀬と 標準入出力通信ができたのだから、シェルにもできるだろう。
調べよう。

どのシェルを使う?

ググると ぱっと見 bash しか出てこない。じゃあ bash で。

エディターは Ubuntu には gedit が最初からインストールされているので、という説もあったが わたしのにはインストールされていなかったので、わたしの環境で最初からインストールされている nano でいいや……。

「シェルスクリプト入門 書き方のまとめ」 (Memo on the Web)
http://motw.mods.jp/shellscript/tutorial.html

mkdir jikken
cd jikken
nano tamesi1
#!/bin/sh
echo "hello, world"

[Ctrl]+[O]

tamesi1 で名前を付けて保存。

おっ、テキストに色が付いた。

[Ctrl]+[X]

で nano エディターを終了。

./tamesi1
-bash: ./tamesi1: Permission denied

パーミッションがあるのか。

ls -an
total 12
drwxrwxr-x 2 1000 1000 4096 Mar  5 16:30 .
drwxr-xr-x 6 1000 1000 4096 Mar  5 16:28 ..
-rw-rw-r-- 1 1000 1000   30 Mar  5 16:30 tamesi1

じゃあ

chmod 765 tamesi1

とかでいいんだろうか? 無理。ルート権限がいるのか。

sudo su -
~パスワード入力~
chmod 765 tamesi1
ls -an
total 12
drwxrwxr-x 2 1000 1000 4096 Mar  5 16:30 .
drwxr-xr-x 6 1000 1000 4096 Mar  5 16:28 ..
-rwxrw-r-x 1 1000 1000   30 Mar  5 16:30 tamesi1
   ~     ~
   ※ここが変わった
./tamesi1
hello, world

おっ、いけた。
じゃあ bin フォルダーの中でシェル・スクリプトを書くか。

cd ../shogi/apery-SDT4/bin

あっ! こっちじゃないや。

cd ../../ukamuse_sdt4/bin

.exe ファイルとか置いてあるんだが、Ubuntu じゃ使わないだろ……、消しておくか。

rm ukamuse_sdt4_bmi2.exe
rm ukamuse_sdt4_sse2.exe
rm ukamuse_sdt4_sse41.exe
rm ukamuse_sdt4_sse42.exe

テキストエディタに書いてコピー、PuTTY で左クリックで貼り付け、[Enter]キー1回で全部終わり。

シェル・スクリプトを書こう

じゃあ、こんな風に書けばいいんだろうか?

まずは bench で試し。

nano tamesi1
#!/bin/sh
./apery
bench

これも PuTTY へ右クリックで貼り付け。保存して nano 終了。

./tamesi1
-su: ./tamesi1: Permission denied
ls -an
total 852
drwxr-xr-x 3 0 0   4096 Mar  5 16:44 .
drwxr-xr-x 6 0 0   4096 Mar  5 02:33 ..
drwxr-xr-x 2 0 0   4096 Oct  7 11:05 20161007
-rwxr-xr-x 1 0 0 848120 Mar  5 02:47 apery
-rw-r--r-- 1 0 0   1531 Mar  5 03:04 benchmark.sfen
-rw-r--r-- 1 0 0     24 Mar  5 16:44 tamesi1
chmod 744 tamesi1
ls -n
total 844
drwxr-xr-x 2 0 0   4096 Oct  7 11:05 20161007
-rwxr-xr-x 1 0 0 848120 Mar  5 02:47 apery
-rw-r--r-- 1 0 0   1531 Mar  5 03:04 benchmark.sfen
-rwxr--r-- 1 0 0     24 Mar  5 16:44 tamesi1
   ~
   ※ここが変わった
./tamesi1

待機ループに入ったようだが、bench を入力するのが早すぎるのだろうか?

bench

手入力すると行ける。数秒待機してから bench を入力するようにした方がいいのか?

[Ctrl]+[C] でブロックを抜ける。

数秒待ってから入力しよう

「【 sleep 】 指定された時間,停止する」 (ITPro)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230884/?rt=nocnt

じゃあ、浮かむ瀬起動から 10秒待ってから bench と入力するようにしよう。

#!/bin/sh
./apery
sleep 10s
bench

nano で編集して、コマンドラインで実行。

ブロックされている。じゃあ、書き方が違うのか。こうか。

#!/bin/sh
./apery
sleep 10s
echo 'bench'

ブロックされたままだが……。 ./apery の行でブロックしているんじゃないか? だったら。
これでどうか?

#!/bin/sh
./apery &
sleep 3s
echo 'bench' | ./apery

ビンゴ! いけた。
じゃあ、sleep とか要るのだろうか?

#!/bin/sh
./apery &
echo 'bench' | ./apery

これでもいけた。じゃあ、bench はこれで。

対局も、シェル・スクリプトで書いてみよう

お出かけのあと追記する。

PuTTY に IPアドレスを入れて SSHプロトコルでログイン。
ユーザー名とパスワードを入れる。

sudo su -

またパスワードを入れる。

cd ../home/ユーザー名/shogi/ukamuse_sdt4/bin
ls

よし。

tamesi2 ファイルを作ってみよう。

nano tamesi2
#!/bin/sh
./apery &
echo 'usi' | ./apery
ls -n
~略~
-rw-r--r-- 1 0 0     41 Mar  5 18:25 tamesi2
chmod 744 tamesi2
ls -n
~略~
-rwxr--r-- 1 0 0     41 Mar  5 18:25 tamesi2
./tamesi2
id name ukamuse_SDT4
~略~
usiok

コマンドの出力を、シェルの変数で受け取ろう

この 浮かむ瀬 の出力を シェル・スクリプトで受け取るには どうすればいいのか?
テキスト・ファイルを経由すれば、それはできそうだが……?

「関数の使用方法」 (UNIX & Linux コマンド・シェルスクリプト リファレンス)
http://shellscript.sunone.me/function.html

これは関数の例か。リダイレクトで変数に渡せないものか。

「コマンドの実行結果を変数に設定する」 (UNIX & Linux コマンド・シェルスクリプト リファレンス)
http://shellscript.sunone.me/variable.html#コマンドの実行結果を変数に設定する

VAR=`command`
echo $VAR

へぇ。

VAR=$(command)
echo $VAR

ほう。$( ) の方はネストも可能らしい。

var=$(expr $(expr $(date '+%Y') + $(date '+%m')) + $(date '+%d'))
echo $VAR

なんのこっちゃ分からんが 使うこともあるかもしれない。
じゃあ こうか。

nano tamesi3
#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)
echo '(^o^)$VAR'
chmod 744 tamesi3
./tamesi3
(^o^)$VAR

うーむ。

#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)
echo '(^o^)${VAR}'
./tamesi3
(^o^)${VAR}

うーむ。

#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)
echo '(^o^)$(VAR)'
./tamesi3
(^o^)$(VAR)

うーむ。

「【 複数の変数を連結する 】」 (ITPro)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060228/231154/

#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)
echo "(^o^)${VAR}"
./tamesi3
(^o^)id name ukamuse_SDT4
~略~
usiok

おーっ!

bash で複数行テキストを1行毎に分割し、各行に対して 対応する処理を書こう

C#言語とかなら簡単なのに……。bashスクリプトではどうやるんだ。

「【bash】行ごとに処理する」 (Qiita)
http://qiita.com/kazu56/items/83340a2e284298b9e237

cat コマンドって何だ?

「【Linuxコマンド集】3分でわかるcat コマンドの使い方」 (エンジニアの入り口)
http://eng-entrance.com/linux_command_cat

ふーん。引数で指定したファイルの内容を標準出力へ1行ずつ出力するのか。
じゃあ、試しに。

あれ! せっかく変数で受け取ったのに、ファイル経由だと意味ないじゃないか。
じゃあ、これでどうか?

tamesi4

#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)

# 区切り文字は NewLine で。
IFS=$'\n'
for line in $VAR
do
echo "(^o^)$line"
done

やっべ、PuTTY での日本語フォント表示が怪しいぜ。読めるからいいか……。

chmod 744 tamesi4
./tamesi4
(^o^)id
(^o^)ame ukamuse_SDT4
id author Hiraoka Takuya

optio
(^o^)
(^o^)ame Best_Book_Move type check default false
optio
(^o^)
(^o^)ame Book_File type stri
(^o^)g default book/20150503/book.bi
(^o^)
optio
(^o^)
(^o^)ame Byoyomi_Margi
(^o^) type spi
(^o^) default 500 mi
(^o^) 0 max 2147483647
optio
(^o^)
(^o^)ame Clear_Hash type butto
(^o^)
optio
(^o^)
(^o^)ame Draw_Ply type spi
(^o^) default 256 mi
(^o^) 1 max 2147483647
optio
(^o^)
(^o^)ame E
(^o^)gi
(^o^)e_Name type stri
(^o^)g default ukamuse_SDT4
optio
(^o^)
(^o^)ame Max_Book_Ply type spi
(^o^) default 32767 mi
(^o^) 0 max 32767
optio
(^o^)
(^o^)ame Max_Ra
(^o^)dom_Score_Diff type spi
(^o^) default 0 mi
(^o^) 0 max 32600
optio
(^o^)
(^o^)ame Max_Ra
(^o^)dom_Score_Diff_Ply type spi
(^o^) default 32767 mi
(^o^) 0 max 32767
optio
(^o^)
(^o^)ame Mi
(^o^)_Book_Ply type spi
(^o^) default 32767 mi
(^o^) 0 max 32767
optio
(^o^)
(^o^)ame Mi
(^o^)_Book_Score type spi
(^o^) default -180 mi
(^o^) -32601 max 32601
optio
(^o^)
(^o^)ame Mi
(^o^)imum_Thi
(^o^)ki
(^o^)g_Time type spi
(^o^) default 20 mi
(^o^) 0 max 2147483647
optio
(^o^)
(^o^)ame Move_Overhead type spi
(^o^) default 30 mi
(^o^) 0 max 5000
optio
(^o^)
(^o^)ame MultiPV type spi
(^o^) default 1 mi
(^o^) 1 max 594
optio
(^o^)
(^o^)ame Ow
(^o^)Book type check default true
optio
(^o^)
(^o^)ame Slow_Mover type spi
(^o^) default 89 mi
(^o^) 1 max 1000
optio
(^o^)
(^o^)ame Slow_Mover_10 type spi
(^o^) default 10 mi
(^o^) 1 max 1000
optio
(^o^)
(^o^)ame Slow_Mover_16 type spi
(^o^) default 20 mi
(^o^) 1 max 1000
optio
(^o^)
(^o^)ame Slow_Mover_20 type spi
(^o^) default 40 mi
(^o^) 1 max 1000
optio
(^o^)
(^o^)ame Threads type spi
(^o^) default 2 mi
(^o^) 1 max 256
optio
(^o^)
(^o^)ame Time_Margi
(^o^) type spi
(^o^) default 4500 mi
(^o^) 0 max 2147483647
optio
(^o^)
(^o^)ame USI_Hash type spi
(^o^) default 256 mi
(^o^) 1 max 1048576
optio
(^o^)
(^o^)ame USI_Po
(^o^)der type check default true
usiok

なんだこりゃ。

文字 n で改行されているのでは……?
区切り文字の行頭に # を付けて、いったんコメントアウトしてみよう。

#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)

# 区切り文字は NewLine で。
# IFS=$'\n'
for line in $VAR
do
echo "(^o^)$line"
done
./tamesi4
(^o^)id
(^o^)name
(^o^)ukamuse_SDT4
(^o^)id
(^o^)author
(^o^)Hiraoka
(^o^)Takuya
(^o^)option
(^o^)name
(^o^)Best_Book_Move
(^o^)type
(^o^)check
(^o^)default
(^o^)false
(^o^)option
(^o^)name
~以下略~

ホワイトスペース全部 区切り文字なのか。

試しに \n をダブルクォーテーションで囲んでみよう。

IFS=$"\n"

だめ。

IFS=$"\n"

だめ。

IFS=$'\t\n'

だめ。文字 t まで消えた。

IFS=$'\\n'

だめ。

IFS=$"\\n"

だめ。

IFS="\\n"

だめ。

「bashのIFSに改行のみを設定するには」 (計算機と戯れる日々)
http://d.hatena.ne.jp/n9d/20090313/1236912316

IFS='
'

いけた。

./tamesi4
(^o^)id name ukamuse_SDT4
(^o^)id author Hiraoka Takuya
(^o^)option name Best_Book_Move type check default false
(^o^)option name Book_File type string default book/20150503/book.bin
(^o^)option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
~以下略~

じゃあ、ひとまず1行ずつには区切れた。
次は、区切った1行を 半角スペースで区切りたい。

ループをネストすると 区切り文字指定 のリセットの手間が増えそうなので、
行分割した結果は配列に入れて 別ループにしたい。

配列を使うには?

「bash 配列まとめ」 (Qiita)
http://qiita.com/b4b4r07/items/e56a8e3471fb45df2f59

なんだこの、ややこしいの。
可変長配列の作り方が分からない。
分割すると同時に、配列で取得することはできるだろうか?

「BashでStringから配列に変換してfor文で回す」 (くらげになりたい。)
http://wannabe-jellyfish.hatenablog.com/entry/2015/01/10/004554

'''

配列に変換

array_text=(echo $text)
'''

やってみよう。

nano tamesi5
#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)

# 改行で分割して配列に入れる
LINES=(`echo $VAR`)
for line in $LINES
do
echo "(^o^)$line"
done

あれ? 今まで シングル・クォーテーションと バック・クォーテーションを間違えていたのだろうか?

chmod 744 tamesi5
./tamesi5
./tamesi5: 6: ./tamesi5: Syntax error: "(" unexpected

これの間違いなんじゃないか?

LINES=$("echo $VAR")

うわ、なんか 出力がおかしい。こうか。

LINES=$(echo $VAR)
./tamesi5
(^o^)id
(^o^)name
(^o^)ukamuse_SDT4
(^o^)id
(^o^)author

区切り文字は echo でも設定しないといけないのか……?

あれ、tamesi5 が掴まれたままみたいだ。

kill %1

止めてはみたが。うーむ。

ls -an
~中略~
-rwxr--r-- 1 0 0    156 Mar  5 20:01 tamesi5
-rw-r--r-- 1 0 0   1024 Mar  5 20:01 .tamesi5.swp

ロック・ファイルが残っているんじゃないか? 消していいのだろうか。

rm .tamesi5.swp

tamesi5 編集。これでどうか。

# 区切り文字IFSは改行だけで分割して配列に入れる
IFS='
'
LINES=$(echo $VAR)

なんか出力結果が1行につながってしまった。
じゃあ、配列への要素追加を使ってみよう。

#!/bin/sh
./apery &
VAR=$(echo 'usi' | ./apery)

# 行分割して配列に入れる
LINES=()
# 区切り文字は 改行だけで。
IFS='
'
for line in $VAR
do
LINES=("${LINES[@]}" $line)
done

for line in $LINES
do
echo "(^o^)$line"
done
./tamesi5
./tamesi5: 6: ./tamesi5: Syntax error: "(" unexpected

うーむ。

「bashとかshで配列を扱う。」 (自分の仕事を憎むには人生は余りにも短い)
http://garapon.hatenablog.com/entry/20100129/1264780520

sh には配列が無いので、 bash を使うのがいいらしい。
じゃあファイルの冒頭を

#!/bin/sh

から

#!/bin/bash

に変更する。

./tamesi5
(^o^)id name ukamuse_SDT4

1行だけ返ってきた。
配列の要素数を確認しよう。

echo ${#array[@]}
./tamesi5
0
(^o^)id name ukamuse_SDT4

うーむ。
こうか。

echo ${#LINES[@]}
./tamesi5
26
(^o^)id name ukamuse_SDT4

配列に分割するところまではいけたのだろうか。

「配列のデータを参照する」 (Qiita)
http://qiita.com/b4b4r07/items/e56a8e3471fb45df2f59

じゃあ、こうか。

i=0
for line in ${LINES[@]}
do
    echo "(^q^)[$i] = $line"
    let i++
done
./tamesi5
26
(^q^)[0] = id name ukamuse_SDT4
(^q^)[1] = id author Hiraoka Takuya
(^q^)[2] = option name Best_Book_Move type check default false
(^q^)[3] = option name Book_File type string default book/20150503/book.bin
(^q^)[4] = option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
(^q^)[5] = option name Clear_Hash type button
(^q^)[6] = option name Draw_Ply type spin default 256 min 1 max 2147483647
(^q^)[7] = option name Engine_Name type string default ukamuse_SDT4
(^q^)[8] = option name Max_Book_Ply type spin default 32767 min 0 max 32767
(^q^)[9] = option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
(^q^)[10] = option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
(^q^)[11] = option name Min_Book_Ply type spin default 32767 min 0 max 32767
(^q^)[12] = option name Min_Book_Score type spin default -180 min -32601 max 32601
(^q^)[13] = option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
(^q^)[14] = option name Move_Overhead type spin default 30 min 0 max 5000
(^q^)[15] = option name MultiPV type spin default 1 min 1 max 594
(^q^)[16] = option name OwnBook type check default true
(^q^)[17] = option name Slow_Mover type spin default 89 min 1 max 1000
(^q^)[18] = option name Slow_Mover_10 type spin default 10 min 1 max 1000
(^q^)[19] = option name Slow_Mover_16 type spin default 20 min 1 max 1000
(^q^)[20] = option name Slow_Mover_20 type spin default 40 min 1 max 1000
(^q^)[21] = option name Threads type spin default 2 min 1 max 256
(^q^)[22] = option name Time_Margin type spin default 4500 min 0 max 2147483647
(^q^)[23] = option name USI_Hash type spin default 256 min 1 max 1048576
(^q^)[24] = option name USI_Ponder type check default true
(^q^)[25] = usiok

よし!

配列の要素の中身を、スペース区切りにしよう

これでどうか?

nano tamesi6
#!/bin/bash
./apery &
VAR=$(echo 'usi' | ./apery)

# 行分割して配列に入れる
LINES=()
# 区切り文字は 改行だけで
IFS='
'
for line in $VAR
do
LINES=("${LINES[@]}" $line)
done
# echo ${#LINES[@]}

iLine=0
for line in ${LINES[@]}
do
    echo "(^q^)[$iLine] = $line"

    # 行分割して配列に入れる
    TOKENS=()
    # 区切り文字は 半角スペースだけで
    IFS=' '

    iToken=0
    for token in $line
    do
        TOKENS=("${TOKENS[@]}" $token)
        echo "(^q^)[$iLine][$iToken] = $token"
        let iToken++
    done

    let iLine++
done
chmod 744 tamesi6
./tamesi6
(^q^)[0] = id name ukamuse_SDT4
(^q^)[0][0] = id
(^q^)[0][1] = name
(^q^)[0][2] = ukamuse_SDT4
(^q^)[1] = id author Hiraoka Takuya
(^q^)[1][0] = id
(^q^)[1][1] = author
(^q^)[1][2] = Hiraoka
(^q^)[1][3] = Takuya
(^q^)[2] = option name Best_Book_Move type check default false
(^q^)[2][0] = option
(^q^)[2][1] = name
(^q^)[2][2] = Best_Book_Move
(^q^)[2][3] = type
(^q^)[2][4] = check
(^q^)[2][5] = default
(^q^)[2][6] = false
(^q^)[3] = option name Book_File type string default book/20150503/book.bin
(^q^)[3][0] = option
(^q^)[3][1] = name
(^q^)[3][2] = Book_File
(^q^)[3][3] = type
(^q^)[3][4] = string
(^q^)[3][5] = default
(^q^)[3][6] = book/20150503/book.bin
(^q^)[4] = option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
(^q^)[4][0] = option
(^q^)[4][1] = name
(^q^)[4][2] = Byoyomi_Margin
(^q^)[4][3] = type
(^q^)[4][4] = spin
(^q^)[4][5] = default
(^q^)[4][6] = 500
(^q^)[4][7] = min
(^q^)[4][8] = 0
(^q^)[4][9] = max
(^q^)[4][10] = 2147483647
(^q^)[5] = option name Clear_Hash type button
(^q^)[5][0] = option
(^q^)[5][1] = name
(^q^)[5][2] = Clear_Hash
(^q^)[5][3] = type
(^q^)[5][4] = button
(^q^)[6] = option name Draw_Ply type spin default 256 min 1 max 2147483647
(^q^)[6][0] = option
(^q^)[6][1] = name
(^q^)[6][2] = Draw_Ply
(^q^)[6][3] = type
(^q^)[6][4] = spin
(^q^)[6][5] = default
(^q^)[6][6] = 256
(^q^)[6][7] = min
(^q^)[6][8] = 1
(^q^)[6][9] = max
(^q^)[6][10] = 2147483647
(^q^)[7] = option name Engine_Name type string default ukamuse_SDT4
(^q^)[7][0] = option
(^q^)[7][1] = name
(^q^)[7][2] = Engine_Name
(^q^)[7][3] = type
(^q^)[7][4] = string
(^q^)[7][5] = default
(^q^)[7][6] = ukamuse_SDT4
(^q^)[8] = option name Max_Book_Ply type spin default 32767 min 0 max 32767
(^q^)[8][0] = option
(^q^)[8][1] = name
(^q^)[8][2] = Max_Book_Ply
(^q^)[8][3] = type
(^q^)[8][4] = spin
(^q^)[8][5] = default
(^q^)[8][6] = 32767
(^q^)[8][7] = min
(^q^)[8][8] = 0
(^q^)[8][9] = max
(^q^)[8][10] = 32767
(^q^)[9] = option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
(^q^)[9][0] = option
(^q^)[9][1] = name
(^q^)[9][2] = Max_Random_Score_Diff
(^q^)[9][3] = type
(^q^)[9][4] = spin
(^q^)[9][5] = default
(^q^)[9][6] = 0
(^q^)[9][7] = min
(^q^)[9][8] = 0
(^q^)[9][9] = max
(^q^)[9][10] = 32600
(^q^)[10] = option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
(^q^)[10][0] = option
(^q^)[10][1] = name
(^q^)[10][2] = Max_Random_Score_Diff_Ply
(^q^)[10][3] = type
(^q^)[10][4] = spin
(^q^)[10][5] = default
(^q^)[10][6] = 32767
(^q^)[10][7] = min
(^q^)[10][8] = 0
(^q^)[10][9] = max
(^q^)[10][10] = 32767
(^q^)[11] = option name Min_Book_Ply type spin default 32767 min 0 max 32767
(^q^)[11][0] = option
(^q^)[11][1] = name
(^q^)[11][2] = Min_Book_Ply
(^q^)[11][3] = type
(^q^)[11][4] = spin
(^q^)[11][5] = default
(^q^)[11][6] = 32767
(^q^)[11][7] = min
(^q^)[11][8] = 0
(^q^)[11][9] = max
(^q^)[11][10] = 32767
(^q^)[12] = option name Min_Book_Score type spin default -180 min -32601 max 32601
(^q^)[12][0] = option
(^q^)[12][1] = name
(^q^)[12][2] = Min_Book_Score
(^q^)[12][3] = type
(^q^)[12][4] = spin
(^q^)[12][5] = default
(^q^)[12][6] = -180
(^q^)[12][7] = min
(^q^)[12][8] = -32601
(^q^)[12][9] = max
(^q^)[12][10] = 32601
(^q^)[13] = option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
(^q^)[13][0] = option
(^q^)[13][1] = name
(^q^)[13][2] = Minimum_Thinking_Time
(^q^)[13][3] = type
(^q^)[13][4] = spin
(^q^)[13][5] = default
(^q^)[13][6] = 20
(^q^)[13][7] = min
(^q^)[13][8] = 0
(^q^)[13][9] = max
(^q^)[13][10] = 2147483647
(^q^)[14] = option name Move_Overhead type spin default 30 min 0 max 5000
(^q^)[14][0] = option
(^q^)[14][1] = name
(^q^)[14][2] = Move_Overhead
(^q^)[14][3] = type
(^q^)[14][4] = spin
(^q^)[14][5] = default
(^q^)[14][6] = 30
(^q^)[14][7] = min
(^q^)[14][8] = 0
(^q^)[14][9] = max
(^q^)[14][10] = 5000
(^q^)[15] = option name MultiPV type spin default 1 min 1 max 594
(^q^)[15][0] = option
(^q^)[15][1] = name
(^q^)[15][2] = MultiPV
(^q^)[15][3] = type
(^q^)[15][4] = spin
(^q^)[15][5] = default
(^q^)[15][6] = 1
(^q^)[15][7] = min
(^q^)[15][8] = 1
(^q^)[15][9] = max
(^q^)[15][10] = 594
(^q^)[16] = option name OwnBook type check default true
(^q^)[16][0] = option
(^q^)[16][1] = name
(^q^)[16][2] = OwnBook
(^q^)[16][3] = type
(^q^)[16][4] = check
(^q^)[16][5] = default
(^q^)[16][6] = true
(^q^)[17] = option name Slow_Mover type spin default 89 min 1 max 1000
(^q^)[17][0] = option
(^q^)[17][1] = name
(^q^)[17][2] = Slow_Mover
(^q^)[17][3] = type
(^q^)[17][4] = spin
(^q^)[17][5] = default
(^q^)[17][6] = 89
(^q^)[17][7] = min
(^q^)[17][8] = 1
(^q^)[17][9] = max
(^q^)[17][10] = 1000
(^q^)[18] = option name Slow_Mover_10 type spin default 10 min 1 max 1000
(^q^)[18][0] = option
(^q^)[18][1] = name
(^q^)[18][2] = Slow_Mover_10
(^q^)[18][3] = type
(^q^)[18][4] = spin
(^q^)[18][5] = default
(^q^)[18][6] = 10
(^q^)[18][7] = min
(^q^)[18][8] = 1
(^q^)[18][9] = max
(^q^)[18][10] = 1000
(^q^)[19] = option name Slow_Mover_16 type spin default 20 min 1 max 1000
(^q^)[19][0] = option
(^q^)[19][1] = name
(^q^)[19][2] = Slow_Mover_16
(^q^)[19][3] = type
(^q^)[19][4] = spin
(^q^)[19][5] = default
(^q^)[19][6] = 20
(^q^)[19][7] = min
(^q^)[19][8] = 1
(^q^)[19][9] = max
(^q^)[19][10] = 1000
(^q^)[20] = option name Slow_Mover_20 type spin default 40 min 1 max 1000
(^q^)[20][0] = option
(^q^)[20][1] = name
(^q^)[20][2] = Slow_Mover_20
(^q^)[20][3] = type
(^q^)[20][4] = spin
(^q^)[20][5] = default
(^q^)[20][6] = 40
(^q^)[20][7] = min
(^q^)[20][8] = 1
(^q^)[20][9] = max
(^q^)[20][10] = 1000
(^q^)[21] = option name Threads type spin default 2 min 1 max 256
(^q^)[21][0] = option
(^q^)[21][1] = name
(^q^)[21][2] = Threads
(^q^)[21][3] = type
(^q^)[21][4] = spin
(^q^)[21][5] = default
(^q^)[21][6] = 2
(^q^)[21][7] = min
(^q^)[21][8] = 1
(^q^)[21][9] = max
(^q^)[21][10] = 256
(^q^)[22] = option name Time_Margin type spin default 4500 min 0 max 2147483647
(^q^)[22][0] = option
(^q^)[22][1] = name
(^q^)[22][2] = Time_Margin
(^q^)[22][3] = type
(^q^)[22][4] = spin
(^q^)[22][5] = default
(^q^)[22][6] = 4500
(^q^)[22][7] = min
(^q^)[22][8] = 0
(^q^)[22][9] = max
(^q^)[22][10] = 2147483647
(^q^)[23] = option name USI_Hash type spin default 256 min 1 max 1048576
(^q^)[23][0] = option
(^q^)[23][1] = name
(^q^)[23][2] = USI_Hash
(^q^)[23][3] = type
(^q^)[23][4] = spin
(^q^)[23][5] = default
(^q^)[23][6] = 256
(^q^)[23][7] = min
(^q^)[23][8] = 1
(^q^)[23][9] = max
(^q^)[23][10] = 1048576
(^q^)[24] = option name USI_Ponder type check default true
(^q^)[24][0] = option
(^q^)[24][1] = name
(^q^)[24][2] = USI_Ponder
(^q^)[24][3] = type
(^q^)[24][4] = check
(^q^)[24][5] = default
(^q^)[24][6] = true
(^q^)[25] = usiok
(^q^)[25][0] = usiok

いけてるか。

サブルーチンにしよう

1行を分割して配列に入れる部分は サブルーチンにして切り出そう。

nano tamesi7
#!/bin/bash

# 一行をトークン区切り配列へ
# $1...line
Line_To_Tokens(){
    TOKENS=()
    # 区切り文字は 半角スペースだけで
    IFS=' '

    iToken=0
    for token in $1
    do
        TOKENS=("${TOKENS[@]}" $token)
        let iToken++
    done

    # せっかく配列にいれても標準出力へ返すのか……
    echo ${TOKENS[@]}
}

./apery &
VAR=$(echo 'usi' | ./apery)

# 行分割して配列に入れる
LINES=()
# 区切り文字は 改行だけで
IFS='
'
for line in $VAR
do
LINES=("${LINES[@]}" $line)
done

iLine=0
for line in ${LINES[@]}
do
    # 行分割して配列に入れる
    TOKENS=(`Line_To_Tokens $line`)

    echo "(^q^)[$iLine] = ${TOKENS[@]}"

    let iLine++
done
chmod 744 tamesi7
./tamesi7
(^q^)[0] = id name ukamuse_SDT4
(^q^)[1] = id author Hiraoka Takuya
(^q^)[2] = option name Best_Book_Move type check default false
(^q^)[3] = option name Book_File type string default book/20150503/book.bin
(^q^)[4] = option name Byoyomi_Margin type spin default 500 min 0 max 2147483647
(^q^)[5] = option name Clear_Hash type button
(^q^)[6] = option name Draw_Ply type spin default 256 min 1 max 2147483647
(^q^)[7] = option name Engine_Name type string default ukamuse_SDT4
(^q^)[8] = option name Max_Book_Ply type spin default 32767 min 0 max 32767
(^q^)[9] = option name Max_Random_Score_Diff type spin default 0 min 0 max 32600
(^q^)[10] = option name Max_Random_Score_Diff_Ply type spin default 32767 min 0 max 32767
(^q^)[11] = option name Min_Book_Ply type spin default 32767 min 0 max 32767
(^q^)[12] = option name Min_Book_Score type spin default -180 min -32601 max 32601
(^q^)[13] = option name Minimum_Thinking_Time type spin default 20 min 0 max 2147483647
(^q^)[14] = option name Move_Overhead type spin default 30 min 0 max 5000
(^q^)[15] = option name MultiPV type spin default 1 min 1 max 594
(^q^)[16] = option name OwnBook type check default true
(^q^)[17] = option name Slow_Mover type spin default 89 min 1 max 1000
(^q^)[18] = option name Slow_Mover_10 type spin default 10 min 1 max 1000
(^q^)[19] = option name Slow_Mover_16 type spin default 20 min 1 max 1000
(^q^)[20] = option name Slow_Mover_20 type spin default 40 min 1 max 1000
(^q^)[21] = option name Threads type spin default 2 min 1 max 256
(^q^)[22] = option name Time_Margin type spin default 4500 min 0 max 2147483647
(^q^)[23] = option name USI_Hash type spin default 256 min 1 max 1048576
(^q^)[24] = option name USI_Ponder type check default true
(^q^)[25] = usiok

よし、意図した通りには動いてるだろ。サブルーチン化した嬉しみが少ないが……。

仕分けしよう

ここで、各行の1単語目(1トークン目)を見ると

-id
-option
-usiok

のいずれかであることが分かるだろう。ここで取り合えず id と option は無視して、usiok があるかどうかだけ調べるルーチンを書こう。

usiok があれば、浮かむ瀬に isready という文字列を送るものとする。

テキストの 1行目を取得するには、

「How do I read first line using cat」 (stack overflow)
http://stackoverflow.com/questions/6114119/how-do-i-read-first-line-using-cat

head -n 1 file.txt

を使えばいいのだろうか。head コマンドの動作確認をしてみよう。

FIRST_TOKEN=(`head -n 1 ${TOKENS[@]}`)
(^q^)[1] =
head: cannot open 'option name Best_Book_Move type check default false' for reading: No such file or directory

ファイルじゃないとダメなんじゃないだろうか?

「【 文字列を抜き出す「cut」 】」 (ITPro)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060228/231159/

FIRST_TOKEN=(`echo ${TOKENS[@]} | cut -d "
"`)
(^q^)[0] =
cut: you must specify a list of bytes, characters, or fields
Try 'cut --help' for more information.

うーむ。
シェルのコマンドは ほとんど 標準入出力 を介すのだろうか。
だったら 素直に ファイルを経由した方がいいのか?
書き直してみよう。

echo は複数行は出力してくれないんだろうか?

nano tamesi8
#!/bin/bash

# 引数1をスペース区切りにし、最初のトークンを出力
# $1...line
Line_To_FirstToken(){
    TOKENS=()
    # 区切り文字は 半角スペースだけで
    IFS=' '

    for token in $1
    do
        echo $token
        return 0
    done
}

./apery &
VAR=$(echo 'usi' | ./apery)

# 行分割して配列に入れる
LINES=()
# 区切り文字は 改行だけで
IFS='
'
for line in $VAR
do
LINES=("${LINES[@]}" $line)
done

iLine=0
for line in ${LINES[@]}
do
    # 行分割して配列に入れる
    FIRST_TOKEN=(`Line_To_FirstToken $line`)

    echo "(^q^)[$iLine] = $FIRST_TOKEN"

    let iLine++
done
chmod 744 tamesi8
./tamesi8
./tamesi8
(^q^)[0] = id
(^q^)[1] = id
(^q^)[2] = option
(^q^)[3] = option
(^q^)[4] = option
(^q^)[5] = option
(^q^)[6] = option
(^q^)[7] = option
(^q^)[8] = option
(^q^)[9] = option
(^q^)[10] = option
(^q^)[11] = option
(^q^)[12] = option
(^q^)[13] = option
(^q^)[14] = option
(^q^)[15] = option
(^q^)[16] = option
(^q^)[17] = option
(^q^)[18] = option
(^q^)[19] = option
(^q^)[20] = option
(^q^)[21] = option
(^q^)[22] = option
(^q^)[23] = option
(^q^)[24] = option
(^q^)[25] = usiok

とりあえず 最初のトークンは取れるものの、すっきりしない。

bash じゃなくて、将棋所相当のプログラムを C# で書いて 浮かむ瀬 は別プロセスで動かして通信したらいいんじゃないか。

じゃあ、mono をインストールした方がいいのか?

Ubuntu に mono をインストールしよう

LinuxではC#は人気ないのか。

「Compiling Mono on Linux」 (Mono)
http://www.mono-project.com/docs/compiling-mono/linux/

こんなコマンド叩いたらいいんだろうか?

sudo apt-get install git autoconf libtool automake build-essential mono-devel gettext cmake

なんか動いた。

After this operation, 132 MB of additional disk space will be used.
Do you want to continue? [Y/n]

じゃあ、どんどん進んでいこう。

done.

もうインストール終わった。
じゃあ C#言語で ハローワールドを書いてみるか。

nano ShogiServer.cs
using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hello, world");
        }
    }
}

nano は C# 書いても色ついてくれないのか。

どうやってコンパイルするんだ。
というか いつまで コマンドラインなんだ。GUI は入れるべきか。

man mono

だめだ、行数が多すぎる。

mono --version
Mono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug
        LLVM:          supported, not enabled.
        GC:            sgen

おっ、バージョン 4 が入ったぜ。助かるぜ。

「csc.exe を使用したコマンド ラインからのビルド」 (MSDN)
https://msdn.microsoft.com/ja-jp/library/78f4aasd.aspx

C# のコンパイラは csc なのだろうか?

csc ShogiServer.cs
The program 'csc' is currently not installed. You can install it by typing:
apt install chicken-bin

入ってないし……。

「Xamarinの基盤となっている「Mono」と、C#コンパイラー「mcs」」 (buildinsider)
http://www.buildinsider.net/mobile/insidexamarin/02

C# のコンパイラは mcs なのだろうか?

mcs ShogiServer.cs
ls
~略~
ShogiServer.cs
ShogiServer.exe

.exe なんかできているが、Linuxで動くのか?

./ShogiServer.exe
hello, world

へぇ!

C#のMakefile とか書けるのだろうか……。

サンプル・プログラムを作ろう

じゃあ、ひとまず、標準入力で "usi" が飛んできて、"usiok" を返すというサンプル・プログラムを組んでみるか。

tamesi9

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hello, world");
            Console.WriteLine("args.Length=" + args.Length);
            int i = 0;
            foreach (string arg in args)
            {
                Console.WriteLine("args[i]=" + args[i]);
                i++;
            }
        }
    }
}
mcs tamesi9
./tamesi9.exe
hello, world
args.Length=0

じゃあ、

echo 'usi' | ./tamesi9.exe
hello, world
args.Length=0

あー、コマンドライン引数と 標準入力は 違うのか。
じゃあ、

./tamesi9.exe abc def ghi
hello, world
args.Length=3
args[i]=abc
args[i]=def
args[i]=ghi

そうか。
じゃあ、こうか。

nano tamesi10
using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                string line = Console.ReadLine();
                switch (line)
                {
                    case "quit": break;
                    default: Console.WriteLine("(^q^)"+line); break;
                }
            }
        }
    }
}
mcs tamesi10
./tamesi10.exe
start a loop.

よし。

abc
(^q^)abc

よし。

quit

あらっ。

abc
(^q^)

あらら。
[Ctrl]+[C]

あーそうか、switch文 で break しても switch文 を抜けるだけで for文 を抜けないんだ。

rm tamesi10
nano tamesi10

こう。

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                string line = Console.ReadLine();
                switch (line)
                {
                    case "quit": goto gt_EndLoop;
                    default: Console.WriteLine("(^q^)"+line); break;
                }
            }
            gt_EndLoop:
            Console.WriteLine("finished a loop.");
        }
    }
}
mcs tamesi10
./tamesi10.exe
start a loop.
abc
(^q^)abc
quit
finished a loop.

こんどは うまくいった。じゃあ、このプログラムをバックグラウンドで走らせられるだろうか。

./tamesi10.exe &
[1] 14279
start a loop.
jobs
[1]+  Stopped                 ./tamesi10.exe

この、Stopped というのが分からない。

echo 'usi' | ./tamesi10.exe
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
~略~

[Ctrl]+[C]

なんということだ。

どういう理屈だ。

switch文に次の1行を足してはどうか?

case "": break;
./tamesi10.exe &
[3] 14317
start a loop.
jobs
[1]   Stopped                 ./tamesi10.exe
[2]-  Stopped                 nano tamesi10
[3]+  Stopped                 ./tamesi10.exe
kill %1
jobs
[1]   Terminated              ./tamesi10.exe
[2]-  Stopped                 nano tamesi10
[3]+  Stopped                 ./tamesi10.exe
echo 'usi' | ./tamesi10.exe
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
(^q^)
~中略~

だめか。

ReadLine() を止めて、Read() にしてみる。

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                int ch = Console.Read();
                Console.WriteLine("(^q^)ch=" + ch);
            }
            Console.WriteLine("finished a loop.");
        }
    }
}
mcs tamesi10
tamesi10(15,13): warning CS0162: Unreachable code detected
Compilation succeeded - 1 warning(s)
./tamesi10.exe &
[3] 14482
start a loop.
echo 'usi' | ./tamesi10.exe
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1
(^q^)ch=-1

うーむ、-1 って何だ。
じゃあ、-1 は省いて。

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                int ch = Console.Read();
                if (-1 != ch)
                {
                    Console.WriteLine("(^q^)ch=" + ch);
                }
            }
            Console.WriteLine("finished a loop.");
        }
    }
}

ところでいままで、出力が入力と被っているところがあった。

root@tk2-217-18401:/home/アカウント名/shogi/ukamuse_sdt4/bin# start a loop.

これ だめなんじゃないだろうか。

echo 'usi' | ./tamesi10.exe
start a loop.
(^q^)ch=117
(^q^)ch=115
(^q^)ch=105
(^q^)ch=10

さて、今度はどうか。

echo 'abc' | ./tamesi10.exe

反応が返ってこない。
どういう待機状態なのか。

echo 'abc' | ./tamesi10.exe
start a loop.
(^q^)ch=97
(^q^)ch=98
(^q^)ch=99
(^q^)ch=10

どうも、標準入力は1回しか効かないのか? 1回出力すると、2回目の入力は効かないとかルールでもあるのだろうか?

別のメソッドを使ってみよう。

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                string line = Console.In.ReadLine();
                switch (line)
                {
                    case "quit": goto gt_EndLoop;
                    default: Console.WriteLine("(^q^)line=" + line); break;
                }
            }
            gt_EndLoop:
            Console.WriteLine("finished a loop.");
        }
    }
}
./tamesi10.exe &
echo 'usi' | ./tamesi10.exe
(^q^)line=
(^q^)line=
(^q^)line=
(^q^)line=
(^q^)line=
(^q^)line=
(^q^)line=
~中略~

うーむ。null を弾くとどうか?

rm tamesi10
nano tamesi10
using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                string line = Console.In.ReadLine();
                if (null != line)
                {
                    switch (line)
                    {
                        case "quit": goto gt_EndLoop;
                        default: Console.WriteLine("(^q^)line=" + line); break;
                    }
                }
            }
            gt_EndLoop:
            Console.WriteLine("finished a loop.");
        }
    }
}
mcs tamesi10
echo 'usi' | ./tamesi10.exe
start a loop.
(^q^)line=usi
abc
def
ghi
echo 'usi' | ./tamesi10.exe

もう入力は効かない。無限ループで待機できないのだろうか?
別の書き方も試してみる。

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            char[] buffer = new char[256];

            Console.WriteLine("start a loop.");
            for (;;)
            {
                int result = Console.In.ReadBlock(buffer, 0, 255);
                Console.WriteLine("(^q^)result=" + result);
                Console.Write("(^q^)buffer=");
                foreach (char ch in buffer)
                {
                    Console.Write(ch);
                }
                Console.WriteLine("(^_^)");
            }
            Console.WriteLine("finished a loop.");
        }
    }
}
./tamesi10.exe &
echo 'usi' | ./tamesi10.exe
(^q^)result=0
(^q^)buffer=usi
(^_^)
(^q^)result=0
(^q^)buffer=usi
(^_^)
(^q^)result=0
(^q^)buffer=usi
(^_^)
(^q^)result=0
(^q^)buffer=usi
(^_^)
(^q^)result=0
(^q^)buffer=usi
(^_^)

Ubuntu/C# では、入力側のバッファーがフラッシュされてないのか。

入力側のバッファーがフラッシュされてないのか。

「自プロセスの標準入出力」 (SMDN)
http://smdn.jp/programming/netfx/standard_streams/0_console/

「C#で競技プログラミングをし続ける人のためのTips」 (Qiita)
http://qiita.com/Camypaper/items/de6d576fe5513743a50e

じゃあ、異なる入力があるまで無視するように書き換えてみよう。

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            string line_old = "";

            Console.WriteLine("start a loop.");
            for (;;)
            {
                string line = Console.ReadLine(); // Ubuntuでは入力がフラッシュされなかった。
                if (line!=line_old)
                {
                    Console.WriteLine("(^q^)line=" + line);
                    line_old = line;
                    switch (line)
                    {
                        case "quit": goto gt_EndLoop;
                        default: break;
                    }
                }
            }
            gt_EndLoop:
            Console.WriteLine("finished a loop.");
        }
    }
}
./tamesi10.exe
start a loop.
a
(^q^)line=a
b
(^q^)line=b
c
(^q^)line=c
usi
(^q^)line=usi
quit
(^q^)line=quit
finished a loop.

はいっ、ビンゴ! えーっ! なんでそんなバグ残ってんだ。

mono-complete をインストールしましたか?

何それ!

「How to install mono on ubuntu 64-bit v14.04?」 (Ubuntu)
http://askubuntu.com/questions/497358/how-to-install-mono-on-ubuntu-64-bit-v14-04

これやってみるか。

sudo apt-get install mono-complete

インストールが終わると、挙動が変わったwwww

using System;

namespace ShogiServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("start a loop.");
            for (;;)
            {
                string line = Console.ReadLine();
                Console.WriteLine("(^q^)line=" + line);
                switch (line)
                {
                    case "quit": goto gt_EndLoop;
                    default: break;
                }
            }
            gt_EndLoop:
            Console.WriteLine("finished a loop.");
        }
    }
}

ひとまずこれで。コンパイルしなおして、フォア・グラウンドで実行すると、想定した挙動になる。

./tamesi10.exe
start a loop.
a
(^q^)line=a
b
(^q^)line=b
c
(^q^)line=c
quit
(^q^)line=quit
finished a loop.

これを、バックグラウンドで待機させておいて、バックグラウンドで動いているプロセスの標準入力に向かって文字を投げれないだろうか。

そんなことをしたら [Ctrl]+[C] も効かなくなって 入力は将棋サーバーに吸い込まれていくようになってしまった。PuTTY を強制終了させてセッションを落としてもいいのだろうか?

何ごともなく 静かなコンソール画面に再ログインすることができた。

出力をリダイレクトするといいのだろうか?

echo 'usi' | ./tamesi10.exe > log1 &
jobs
[1]+  Running                 echo 'usi' | ./tamesi10.exe > log1 &

おっ、Running なんか初めて見た。

ls
nano log1

[ Reading File ]

また 固まったんだが。画面に

[ Reading File ]

と表示されてるだけで、キー入力はできるのか。

echo 'quit' | ./tamesi10.exe
start a loop.
(^q^)line=quit
finished a loop.
jobs
[1]+  Running                 echo 'usi' | ./tamesi10.exe > log1 &

今 Running している方の ./tamesi10.exe に標準入力を送れないものか。

[Ctrl]+[Z]

なんか分からないがやってみよう。

「What is the difference between Ctrl-z and Ctrl-c in the shell?」 (ask ubuntu)
http://askubuntu.com/questions/510811/what-is-the-difference-between-ctrl-z-and-ctrl-c-in-the-shell

./tamesi10.exe
start a loop.

[Ctrl]+[Z]


[1]+  Stopped                 ./tamesi10.exe

ストップして コマンド・プロンプトが戻ってきたぜ。

bg 1
[1]+ ./tamesi10.exe &

ほう。

fg 1
./tamesi10.exe

戻ってきた。

[Ctrl]+[Z]


[1]+  Stopped                 ./tamesi10.exe

ほう。

fg 1
./tamesi10.exe
usi
(^q^)line=usi

ジョブID が分かってるんだったら手動で「fg 番号」して入力できるが……。
わたしが通信したいんじゃなくて、コンピューター同士に双方向通信させたいんだが、
2つのプロセスを起動させておいて、シェル・スクリプトで fg と bg を使えばいいのだろうか?

標準入出力通信は むずかしいのでは?

ポートを開いてソケット通信したらダメなのか……? なんだろう、この難しい操作。

シェル・スクリプトより、ソケット・プログラムの方が簡単なんじゃないか?

とりあえず 将棋サーバーは ポートを開いてバックグラウンドで走らせておいたらいいんじゃないか。

じゃあ、ウェブ・アプリケーション・サーバーは、ポートを開いている実行プログラムに向かって、文字列を投げる方法があるのか調べてみよう。

PHP とかでソケット通信できるんだろうか?

「socket_create_listen」 (PHPマニュアル)
http://php.net/manual/ja/function.socket-create-listen.php

ソケットの接続を確立したあとの処理はどうするのか?

「fsockopen」 (PHPマニュアル)
http://php.net/manual/ja/function.fsockopen.php

つなぎに行く方は これでいいんだが。

「PHP でサーバソケットプログラミング (1)」 (Rainy Day Codings)
http://rainyday.blog.so-net.ne.jp/2007-02-17

サーバーの待ち受け側は これでいいか。

じゃあ、PHPが動くようにセットアップするか。
レンタル・サーバーの環境は どうなってたっけ。

「料金・サービス仕様」 (SAKURA internet)
http://solution.sakura.ad.jp/windows_vps/specification.html

Apache や PHP のバージョンは自分で調べろということか。

php --version
PHP 7.0.15-0ubuntu0.16.04.4 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.15-0ubuntu0.16.04.4, Copyright (c) 1999-2017, by Zend Technologies

おおっ、PHP 7 だ。

apache2 --version
[Mon Mar 06 02:17:27.188336 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_LOCK_DIR} is not defined
[Mon Mar 06 02:17:27.188706 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_PID_FILE} is not defined
[Mon Mar 06 02:17:27.188743 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_RUN_USER} is not defined
[Mon Mar 06 02:17:27.188765 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_RUN_GROUP} is not defined
[Mon Mar 06 02:17:27.188801 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_LOG_DIR} is not defined
[Mon Mar 06 02:17:27.195871 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_LOG_DIR} is not defined
[Mon Mar 06 02:17:27.196170 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_LOG_DIR} is not defined
[Mon Mar 06 02:17:27.197322 2017] [core:warn] [pid 19747] AH00111: Config variable ${APACHE_LOG_DIR} is not defined
AH00526: Syntax error on line 74 of /etc/apache2/apache2.conf:
Invalid Mutex directory in argument file:${APACHE_LOCK_DIR}

なんか --version という引数は無さげ。

man apache2
apache2 -v
Server version: Apache/2.4.18 (Ubuntu)
Server built:   2016-07-14T12:32:26

apache2 は 2.4.18 か。

じゃあ、PHPの設定とか もう終わってんの? 試してみるか。

PHP を試そうぜ

ブラウザで開いて URLでアクセスすればいいわけなんだが、外に開かれているんだろうか?
ブラウザのURL欄に入れてみる。

http://数字.数字.数字.数字

でた。

Index of /

[ICO]   Name    Last modified   Size    Description
[   ]   gpskick.php 2015-09-12 03:07    351  
[DIR]   html/   2015-09-12 02:40    -    
[   ]   la.php  2015-09-12 03:14    241  
[DIR]   tumecheck/  2015-09-12 03:15    -    
[DIR]   vscom/  2015-09-12 03:03    -    

このフォルダーはどこなのか? Linux のフォルダ構成はよく分からんが、ググろう。

「Ubuntu serverApache」 (Yamamoto's Laboratory)
http://www.yamamo10.jp/yamamoto/comp/home_server/ubuntu_server/apache/index.php

ページは /var/www/index.html みたいな感じであるんだろうか?調べてみよう。

ひゅーっ!

/var/www/html/index.html

何かある。
ソースの中身をみたんだが 気に入らないタグ打ちだぜwwwww

どうも これは トップ階層じゃないみたいだ。

なんか 外からは FileZilla で転送できない。パーミッションを w に変えていいのだろうか?
変えないと作業が進まない。chmod する。

で、ブラウザで開いても PHP は効いてないみたいだ。未設定なのか。

PHP を設定しよう

「【PHP】PHPをインストールしたらやっておきたい設定」 (Qiita)
http://qiita.com/knife0125/items/0e1af52255e9879f9332

etc フォルダーに設定ファイルが入っているのか。

etc フォルダーの下には php と php5 ディレクトリがある。 php5 ではないと思うが。

/etc/php/7.0/cli ディレクトリの中に php.ini があった。

あれっ?

「PHPの設定」 (Sakura VPS マニュアル)
http://www.xn--vps-073b3a72a.com/10.html

わたしの渡されたフォルダー構成と異なるぜ。設定したあとで渡されたんだろうか。

service httpd restart

と叩けば httpデーモンが開始されるのだろうか。

service httpd restart
Failed to restart httpd.service: Unit httpd.service not found.

いろいろ さっぱり状況が分からんな……。

「7. WEBサーバーの設定」 (Sakura VPS マニュアル)
http://www.xn--vps-073b3a72a.com/7.html

「STEP.3:WEBページをアップしよう」 (Sakura VPS マニュアル)
http://www.xn--vps-073b3a72a.com/8.html

var/www/html

さくらVPSのホームページのデフォルトの階層は var/www/html になります。

あれま!

いじったところを 元に戻そう。

多分、なんか、わたしに渡された状態では apache2 と php7.0 は入ってたけど、全然 設定されてない気がする。
かといって アン・インストール/再インストール したら なんか設定されているのが 消えてしまうかもしれない。現状を知らない。

Apache を再起動しよう

Apache 入ってるんだが、リスタート掛けてみるか。

「UbuntuでApacheを再起動する方法・コマンド」 (MiuxMiu)
http://www.miuxmiu.com/archives/2010/03/03/ubuntu_apache_restart_command.html

sudo /etc/init.d/apache2 restart
[ ok ] Restarting apache2 (via systemctl): apache2.service.

なんか すぐ再起動したな。Apache はいて、PHP とは連携してないのだろう。

Apacheの It's works とかいうデフォルトページは html フォルダーの下に見えるんだが、そうか、DNS 設定してないから こんなサブ・ディレクトリでページを見ているんだった。

php.ini を設定しよう

いろいろ コメントアウトされているので、そのコメントを解除していく作業だ。

php.ini のバックアップを取っておく。名前は適当に php.ini.original としておいた。

;error_log = php_errors.log

を、頭のセミコロンを外して、ディレクトリも次のように変えた。

error_log = /var/log/php_errors.log

次に、

;mbstring.language = Japanese

は、頭のセミコロンを外した。

mbstring.language = Japanese

次に、

;mbstring.internal_encoding =

は、次のように変えた。

mbstring.internal_encoding = UTF-8

次に、

;mbstring.http_input =

は、次のように変えた。

mbstring.http_input = auto

次に、

;mbstring.detect_order = auto

は、次のように変えた。

mbstring.detect_order = auto

次に、

expose_php = On

を、次のように変えた。

expose_php = Off

「「expose_php = off」の設定」(エンジニア足立のコーディング日記)
https://www.deep-deep.jp/blog_engineer/archives/3793

このあと、FileZilla で設定ファイルをサーバーに転送し……パーミッションはその都度ルート・ユーザーで変えて、
PuTTY で次のようにコマンドを叩く。

service httpd restart
Failed to restart httpd.service: Unit httpd.service not found.

何か インストールされていないなあ。

Apache はインストールされているけど、インストールしてみよう

yum -y install httpd
The program 'yum' is currently not installed. You can install it by typing:
apt install yum

説明と全然一致しない。

yum をインストールしよう

apt install yum

インストールした。

yum -y install httpd
There are no enabled repos.
 Run "yum repolist all" to see the repos you have.
 You can enable repos with yum-config-manager --enable <repo>

分からん。

yum repolist all
repolist: 0

Apache を再起動するのは、

sudo /etc/init.d/apache2 restart
[ ok ] Restarting apache2 (via systemctl): apache2.service.

できるんだが。じゃあ次のように叩くと?

sudo /etc/init.d/httpd restart
sudo: /etc/init.d/httpd: command not found

init.d ディレクトリに httpd コマンドはあるのだろうか?

/etc/init.d# ls
apache2                 halt                   networking    single
apache-htcacheclean     hostname.sh            ondemand      skeleton
apparmor                hwclock.sh             plymouth      ssh
binfmt-support          irqbalance             plymouth-log  thermald
bootmisc.sh             keyboard-setup         pppd-dns      udev
cgmanager               killprocs              procps        ufw
cgproxy                 kmod                   rc            umountfs
checkfs.sh              memcached              rc.local      umountnfs.sh
checkroot-bootclean.sh  mountall-bootclean.sh  rcS           umountroot
checkroot.sh            mountall.sh            README        urandom
console-setup           mountdevsubfs.sh       reboot        uuidd
cron                    mountkernfs.sh         resolvconf    x11-common
dbus                    mountnfs-bootclean.sh  rsync
dns-clean               mountnfs.sh            rsyslog
grub-common             mysql                  sendsigs

無い。ハイパー・テキスト・トランスファー・プロトコル無い。

httpd なんで無いの?

「Can't find httpd.conf」 (ask ubuntu)
http://askubuntu.com/questions/652095/cant-find-httpd-conf

/etc/apache2# ls
apache2.conf    conf-enabled  magic           mods-enabled  sites-available
conf-available  envvars       mods-available  ports.conf    sites-enabled
sudo /etc/apache2/apache2.conf restart
sudo: /etc/apache2/apache2.conf: command not found

ダメー。

index.php

<?php
echo 'hello, shogi world1';

この内容がそのまま表示されてしまう。じゃあ、HTMLならどうなのか? HTML は表示されている。

echo "<?php phpinfo();"

とコマンドラインに打っても何も起こらない。

現状の環境が使い物にならないので インストールからやり直そう。

「PHPの設定」 (さくらのVPS 設定マニュアル)
http://www.sakura-vps.net/php-settings-for-sakura-vps/

yum -y install php php-mbstring php-mysql
There are no enabled repos.
 Run "yum repolist all" to see the repos you have.
 You can enable repos with yum-config-manager --enable <repo>

「【初心者向け】PHPがブラウザで正しく表示されない時の対処」 (n2p blog)
https://n2p.co.jp/blog/tech/serverside/php-donot-display/

php index.php
hello, shogi world1

これは動いている。じゃあ、phpinfo() を実行してみよう。
表示されるようだ。

じゃあ、パーミッションか?

ls -an
-rw-r--r-- 1    0    0 11510 Sep 12  2015 index.html
-rw-rw-r-- 1 1000 1000    21 Mar  6 04:04 index.php

html は見れるしなあ。

apache の設定に php が書かれていないのだろうか?

ブラウザで開くと

<?php phpinfo();

がそのまま表示されている。

Document Roots
By default, Ubuntu does not allow access through the web browser to any file apart of those located in /var/www, public_html directories (when enabled) and /usr/share (for web applications). If your site is using a web document root located elsewhere (such as in /srv) you may need to whitelist your document root directory in /etc/apache2/apache2.conf.
The default Ubuntu document root is /var/www/html. You can make your own virtual hosts under /var/www. This is different to previous releases which provides better security out of the box.

「PHPが実行されずコメントアウトになる」 (teratail)
https://teratail.com/questions/34508

じゃあ、php5 を削除するか。

「php5.5とかphp5.6をインストールする」 (Qiita)
http://qiita.com/ykyk1218/items/c859870ef8dac79f5e1c

sudo yum remove php-*

一致しないようだ。

無料だと PHPは使えないとかないだろうか。

「UbuntuサーバからPHP5.6を完全に削除」 (エンジニア足立のコーディング日記)
https://www.deep-deep.jp/blog_engineer/archives/4168

完全に削除する場合

sudo apt-get –purge remove php5.6
E: Invalid operation –purge

動かない。

設定ファイルだけ残す場合

sudo apt-get remove php5.6
Reading package lists... Done
Building dependency tree
Reading state information... Done
Note, selecting 'php5.6-json' for regex 'php5.6'
Note, selecting 'php5.6-common' for regex 'php5.6'
Package 'php5.6-common' is not installed, so not removed
Package 'php5.6-json' is not installed, so not removed
The following packages were automatically installed and are no longer required:
  libssl-dev libssl-doc php-cli php-common php-pear php-xml php7.0-cli php7.0-common
  php7.0-json php7.0-opcache php7.0-readline php7.0-xml pkg-php-tools shtool
  zlib1g-dev
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

動いた。が、 0 ばっかりか。

コマンドラインからは php は動かせるので、apache の設定だと思うが。

Apache の設定ファイルで PHP を設定しよう

「モジュール(php7_module)の追加と拡張子(.php)の登録」 (Admin Web)
https://www.adminweb.jp/apache/php/index1.html

httpd.conf が無いので、

/etc/apache2/apache2.conf を開いてみよう。

説明と全然ちがう。パス

「Ubuntu で apache の設定。まとめ。」 (freefielder.jp)
http://freefielder.jp/blog/2012/12/ubuntu-apache.html

/etc/apache2/mods-available/php5.conf を探す。
ある。
あるんだが php5 という名前でいいのか。

        php_admin_flag engine Off

と書いてあるところの頭に # を付け足すことにする。
アパッチを再起動。

sudo service apache2 restart

ブラウザに変化なし。

「ubuntu 16.04 インストール(6) apache, php」 (kashiの日記)
http://verifiedby.me/adiary/086

/etc/apache2/sites-available# ls
000-default.conf  000-default.conf.bak  default-ssl.conf

うーむ、関係なさげ。

「【Ubuntu】PHP 5.6 を PHP 7 へアップグレード」 (Sukohi's tech blog!!)
http://sukohi.blogspot.jp/2016/01/ubuntuphp-56-php-7.html

移動。

/etc/apache2/mods-enabled

ls -an
total 8
drwxr-xr-x 2 0 0 4096 Mar  4 21:09 .
drwxr-xr-x 8 0 0 4096 Mar  4 21:13 ..
lrwxrwxrwx 1 0 0   36 Sep 12  2015 access_compat.load -> ../mods-available/access_compat.load
lrwxrwxrwx 1 0 0   28 Sep 12  2015 alias.conf -> ../mods-available/alias.conf
lrwxrwxrwx 1 0 0   28 Sep 12  2015 alias.load -> ../mods-available/alias.load
lrwxrwxrwx 1 0 0   33 Sep 12  2015 auth_basic.load -> ../mods-available/auth_basic.load
lrwxrwxrwx 1 0 0   33 Sep 12  2015 authn_core.load -> ../mods-available/authn_core.load
lrwxrwxrwx 1 0 0   33 Sep 12  2015 authn_file.load -> ../mods-available/authn_file.load
lrwxrwxrwx 1 0 0   33 Sep 12  2015 authz_core.load -> ../mods-available/authz_core.load
lrwxrwxrwx 1 0 0   33 Sep 12  2015 authz_host.load -> ../mods-available/authz_host.load
lrwxrwxrwx 1 0 0   33 Sep 12  2015 authz_user.load -> ../mods-available/authz_user.load
lrwxrwxrwx 1 0 0   32 Sep 12  2015 autoindex.conf -> ../mods-available/autoindex.conf
lrwxrwxrwx 1 0 0   32 Sep 12  2015 autoindex.load -> ../mods-available/autoindex.load
lrwxrwxrwx 1 0 0   30 Sep 12  2015 deflate.conf -> ../mods-available/deflate.conf
lrwxrwxrwx 1 0 0   30 Sep 12  2015 deflate.load -> ../mods-available/deflate.load
lrwxrwxrwx 1 0 0   26 Sep 12  2015 dir.conf -> ../mods-available/dir.conf
lrwxrwxrwx 1 0 0   26 Sep 12  2015 dir.load -> ../mods-available/dir.load
lrwxrwxrwx 1 0 0   26 Sep 12  2015 env.load -> ../mods-available/env.load
lrwxrwxrwx 1 0 0   29 Sep 12  2015 filter.load -> ../mods-available/filter.load
lrwxrwxrwx 1 0 0   27 Sep 12  2015 mime.conf -> ../mods-available/mime.conf
lrwxrwxrwx 1 0 0   27 Sep 12  2015 mime.load -> ../mods-available/mime.load
lrwxrwxrwx 1 0 0   34 Sep 12  2015 mpm_prefork.conf -> ../mods-available/mpm_prefork.conf
lrwxrwxrwx 1 0 0   34 Sep 12  2015 mpm_prefork.load -> ../mods-available/mpm_prefork.load
lrwxrwxrwx 1 0 0   34 Sep 12  2015 negotiation.conf -> ../mods-available/negotiation.conf
lrwxrwxrwx 1 0 0   34 Sep 12  2015 negotiation.load -> ../mods-available/negotiation.load
lrwxrwxrwx 1 0 0   30 Sep 12  2015 rewrite.load -> ../mods-available/rewrite.load
lrwxrwxrwx 1 0 0   31 Sep 12  2015 setenvif.conf -> ../mods-available/setenvif.conf
lrwxrwxrwx 1 0 0   31 Sep 12  2015 setenvif.load -> ../mods-available/setenvif.load
lrwxrwxrwx 1 0 0   29 Sep 12  2015 status.conf -> ../mods-available/status.conf
lrwxrwxrwx 1 0 0   29 Sep 12  2015 status.load -> ../mods-available/status.load

PHP5 関係は無さそう。

php5 ディレクトリを削除してみよう

etc/php5 というディレクトリがある。削除する。

rm -rf php5/

アパッチを再起動する。

sudo service apache2 restart

これでもダメ。

httpd.conf はどこにあるんだろう。

「PHP7.0をApache2.4にインストール@ウィンドウズ10」 (weblog)
http://weblog.4141.biz/?p=359

Windows の設定なので合わない。

「ubuntu apatche2 でhttpd.confの内容はど」 (YAHOO!JAPAN知恵袋)
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1419833899

/etc/apache2/mods-available ディレクトリに、php5 のファイルがあるので削除してみる。

rm php5.conf
rm php5.load

アパッチを再起動する。

sudo service apache2 restart

これでもダメ。

sudo apt-get remove php
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package 'php' is not installed, so not removed
The following packages were automatically installed and are no longer required:
  libssl-dev libssl-doc php-cli php-common php-pear php-xml php7.0-cli php7.0-common php7.0-json
  php7.0-opcache php7.0-readline php7.0-xml pkg-php-tools shtool zlib1g-dev
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

ダメ。

「Apache 2.x (Unixシステム用)」 (PHPドキュメント)
http://php.net/manual/ja/install.unix.apache2.php

違う。

「Debian GNU/Linux へのインストール」 (PHPドキュメント)
http://php.net/manual/ja/install.unix.debian.php

apt-get install php5-common libapache2-mod-php5 php5-cli
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package libapache2-mod-php5 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Package php5-cli is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  php7.0-cli:i386 php7.0-cli

Package php5-common is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'php5-common' has no installation candidate
E: Package 'libapache2-mod-php5' has no installation candidate
E: Package 'php5-cli' has no installation candidate

うーむ、何かエラーが出ている。

/etc/init.d/apache2 stop
[ ok ] Stopping apache2 (via systemctl): apache2.service.

アパッチを止めると、サイトにアクセスできなくなっている。

/etc/init.d/apache2 start
[ ok ] Starting apache2 (via systemctl): apache2.service.

アパッチを再開させると、サイトにはアクセスできるが、PHPはソースがそのまま出力されている。

apt-cache search php5
bluefish - advanced Gtk+ text editor for web and software development
phing - PHP5 project build system based on Apache Ant
php-auth - Creating an authentication system
php-doc - Documentation for PHP5
php-http-request2 - Provides an easy way to perform HTTP requests
php-letodms-lucene - Document management system - Fulltext search
php-memcache - memcache extension module for PHP5
php-memcached - memcached extension module for PHP5, uses libmemcached
php-net-dns2 - PHP5 Resolver library used to communicate with a DNS server
phpunit - Unit testing suite for PHP5
aptitude search php5
The program 'aptitude' is currently not installed. You can install it by typing:
apt install aptitude

「PHPスクリプトを利用する」 (server world)
https://www.server-world.info/query?os=Debian_8&p=httpd&f=3

aptitude -y install php5 php5-cgi libapache2-mod-php5 php5-common php-pear
The program 'aptitude' is currently not installed. You can install it by typing:
apt install aptitude

aptitude をインストールしよう

「aptitudeをインストールする(Ubuntu 10.10 11.04 64bit)」 (upp)
http://www005.upp.so-net.ne.jp/develop-tom/ub/aptitude-ub.html

sudo apt-get install aptitude

インストールできただろうか?

aptitude -y install php5 php5-cgi libapache2-mod-php5 php5-common php-pear

今度は動いている。

Apacheの設定で、PHPの拡張子を紐付けよう

nano /etc/apache2/mods-enabled/mime.conf

220行目あたりに追記とのこと。

# PHP extension
AddHandler php5-script .php
systemctl restart apache2 

ダメ。

apt-get install php5-common libapache2-mod-php5 php5-cli
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package libapache2-mod-php5 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Package php5-cli is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  php7.0-cli:i386 php7.0-cli

Package php5-common is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'php5-common' has no installation candidate
E: Package 'libapache2-mod-php5' has no installation candidate
E: Package 'php5-cli' has no installation candidate

エラーが出ている。

「PHP + Apacheのインストール - Debian」 (Linux入門)
http://webkaru.net/linux/debian-php-apache-install/

apt-get install apache2 php5
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package php5 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'php5' has no installation candidate

エラーが出ている。

php -v
-su: /usr/bin/php: No such file or directory

エラーが出ている。

php info.php
-su: /usr/bin/php: No such file or directory

PHP が無いということか。

PHP7 をインストールしよう

「Debian(jessie)にPHP 7をインストールする方法」 (約束の地)
http://obel.hatenablog.jp/entry/20160311/1457644814

apt-get install php

インストールする。php 指定で PHP7 相当らしい。

php -v
PHP 7.0.15-0ubuntu0.16.04.4 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.15-0ubuntu0.16.04.4, Copyright (c) 1999-2017, by Zend Technologies

ひとまず PHP7 はインストールした。

Apache と PHP をアンインストールするには?

「Debian 完全にApache2をアンインストールし、再インストールする」 (SE'S BOOK)
https://viewse.blogspot.jp/2011/02/debian-apache2.html

まず、関連するパッケージを文字列検索する。

dpkg --get-selections | grep apache
apache2                                         install
apache2-bin                                     install
apache2-data                                    install
apache2-utils                                   install
libapache2-mod-php5                             install

見つけたパッケージを削除する

apt-get remove --purge apache2 apache2-bin apache2-data apache2-utils libapache2-mod-php5
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.1-0 ssl-cert
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
  apache2* apache2-bin* apache2-data* apache2-utils* libapache2-mod-php5*
0 upgraded, 0 newly installed, 5 to remove and 0 not upgraded.
After this operation, 5,383 kB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 45809 files and directories currently installed.)
Removing apache2 (2.4.18-2ubuntu3.1) ...
Purging configuration files for apache2 (2.4.18-2ubuntu3.1) ...
dpkg: warning: while removing apache2, directory '/var/www/html' not empty so not removed
Removing apache2-bin (2.4.18-2ubuntu3.1) ...
Removing apache2-data (2.4.18-2ubuntu3.1) ...
Removing apache2-utils (2.4.18-2ubuntu3.1) ...
Removing libapache2-mod-php5 (5.5.9+dfsg-1ubuntu4.21) ...
Purging configuration files for libapache2-mod-php5 (5.5.9+dfsg-1ubuntu4.21) ...
Processing triggers for man-db (2.7.5-1) ...
Processing triggers for ufw (0.35-0ubuntu2) ...
dpkg --get-selections | grep apache

これで apache 関連のパッケージを削除した。
次に PHPに関連するパッケージを文字列検索する。

dpkg --get-selections | grep php
php                                             install
php-common                                      install
php-pear                                        deinstall
php5-cli                                        deinstall
php5-common                                     install
php5-json                                       deinstall
php5-memcached                                  deinstall
php5-mysql                                      deinstall
php5-readline                                   deinstall
php7.0                                          install
php7.0-cli                                      install
php7.0-common                                   install
php7.0-fpm                                      install
php7.0-json                                     install
php7.0-opcache                                  install
php7.0-readline                                 install
php7.0-xml                                      deinstall

見つけたパッケージを削除する

apt-get remove --purge php php-common php-pear php5-cli php5-common php5-json php5-memcached php5-mysql php5-readline php7.0 php7.0-cli php7.0-common php7.0-fpm php7.0-json php7.0-opcache php7.0-readline php7.0-xml
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.1-0 ssl-cert
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
  php* php-common* php-pear* php5-cli* php5-common* php5-json* php5-memcached* php5-mysql* php5-readline*
  php7.0* php7.0-cli* php7.0-common* php7.0-fpm* php7.0-json* php7.0-opcache* php7.0-readline* php7.0-xml*
0 upgraded, 0 newly installed, 17 to remove and 0 not upgraded.
After this operation, 14.1 MB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 45161 files and directories currently installed.)
Removing php (1:7.0+35ubuntu6) ...
Removing php7.0 (7.0.15-0ubuntu0.16.04.4) ...
Removing php7.0-fpm (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-fpm (7.0.15-0ubuntu0.16.04.4) ...
dpkg: warning: while removing php7.0-fpm, directory '/etc/php/7.0/fpm/conf.d' not empty so not removed
Removing php7.0-cli (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-cli (7.0.15-0ubuntu0.16.04.4) ...
dpkg: warning: while removing php7.0-cli, directory '/etc/php/7.0/cli/conf.d' not empty so not removed
Removing php7.0-readline (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-readline (7.0.15-0ubuntu0.16.04.4) ...
Removing php7.0-opcache (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-opcache (7.0.15-0ubuntu0.16.04.4) ...
Removing php-pear (1:1.10.1+submodules+notgz-6) ...
Purging configuration files for php-pear (1:1.10.1+submodules+notgz-6) ...
Removing php5-cli (5.5.9+dfsg-1ubuntu4.21) ...
Purging configuration files for php5-cli (5.5.9+dfsg-1ubuntu4.21) ...
Removing php5-common (5.5.9+dfsg-1ubuntu4.21) ...
Purging configuration files for php5-common (5.5.9+dfsg-1ubuntu4.21) ...
dpkg: warning: while removing php5-common, directory '/usr/share/doc/php5-common' not empty so not removed
Removing php5-json (1.3.2-2build1) ...
Purging configuration files for php5-json (1.3.2-2build1) ...
dpkg: warning: while removing php5-json, directory '/usr/lib/php5/20121212' not empty so not removed
Removing php5-memcached (2.1.0-6build1) ...
Purging configuration files for php5-memcached (2.1.0-6build1) ...
dpkg: warning: while removing php5-memcached, directory '/usr/share/php/.registry/.channel.pecl.php.net' not empty so not removed
Removing php5-mysql (5.5.9+dfsg-1ubuntu4.21) ...
Purging configuration files for php5-mysql (5.5.9+dfsg-1ubuntu4.21) ...
Removing php5-readline (5.5.9+dfsg-1ubuntu4.21) ...
Purging configuration files for php5-readline (5.5.9+dfsg-1ubuntu4.21) ...
Removing php7.0-json (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-json (7.0.15-0ubuntu0.16.04.4) ...
Removing php7.0-common (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-common (7.0.15-0ubuntu0.16.04.4) ...
dpkg: warning: while removing php7.0-common, directory '/etc/php/7.0/mods-available' not empty so not removed
Removing php7.0-xml (7.0.15-0ubuntu0.16.04.4) ...
Purging configuration files for php7.0-xml (7.0.15-0ubuntu0.16.04.4) ...
Removing php-common (1:35ubuntu6) ...
Purging configuration files for php-common (1:35ubuntu6) ...
Processing triggers for man-db (2.7.5-1) ...
dpkg --get-selections | grep php

これで apache 関連のパッケージを削除した。

次に再インストールする。

apt-get install apache2 php

アパッチを起動させてみる。

/etc/init.d/apache2 start
[ ok ] Starting apache2 (via systemctl): apache2.service.

404 Not Found になったが、代わりに html フォルダーではなく、その上の階層にアクセスすると
It works! のページが出た。

index.php は相変わらずソースがそのまま出ている。

また設定

nano /etc/apache2/mods-enabled/mime.conf

220行目あたりに追記とのこと。

# PHP extension
AddHandler php5-script .php

アパッチを再起動する。

/etc/init.d/apache2 start
[ ok ] Starting apache2 (via systemctl): apache2.service.

PHP はソースのまま出ている。

「PHPスクリプトを利用する」 (Server World)
https://www.server-world.info/query?os=Ubuntu_16.04&p=httpd&f=3

PHP をインストールする。

apt-get -y install php php-cgi libapache2-mod-php php-common php-pear php-mbstring

アパッチを再起動する。

sudo /etc/init.d/apache2 restart
[ ok ] Restarting apache2 (via systemctl): apache2.service.

おや? phpinfo() が効いた

じゃあ決め手は、

  • アパッチ アンインストール
  • PHP アンインストール
  • アパッチとPHPを同時にインストール
  • apt-get -y install php php-cgi libapache2-mod-php php-common php-pear php-mbstring
  • アパッチ再起動「sudo /etc/init.d/apache2 restart」

このあたりか。途中でディレクトリ階層も変わった。

ブラウザでURLでアクセスして GETクエリー文字列を プログラムに渡せるだろうか?

「HTTPを使うソケット通信」 (rsch)
http://www.rsch.tuis.ac.jp/~mizutani/online/software-basic2002/socket-http.html

サーバー側が欲しいんだが。

「【CakePHP】リクエストの取得方法」 (Qiita)
http://qiita.com/kazu56/items/7d344ccef56deef66a7a

ひとまず PHP でGETクエリー文字列を取得してみるか。

    http://a.b.c.d/html/?shogi=sfen 3/1p1/1P1/3 w - 1 moves

みたいな感じで。

$shogi = $this->request->query('shogi');

なんだこれ、ダメだぜ。

「クエリ文字列の全体を取得する。」 (php pro)
http://www.phppro.jp/qa/1572

「urldecode」 (PHPマニュアル)
http://php.net/manual/ja/function.urldecode.php

例えばこんな感じ。

tamesi1.php

<?php
$query = urldecode($_SERVER['QUERY_STRING']);
echo '(^q^)' . $query . '<br />';
echo 'クリックしろだぜ☆m9(^~^)!<br />';
echo '<a href="http://999.999.999.999/tamesi1.php?shogi=sfen 3/1p1/1P1/3 w - 1 moves">http://999.999.999.999/?shogi=sfen 3/1p1/1P1/3 w - 1 moves</a><br />';

で、サーバー側でプログラムが動いているとして、どうやって この文字列を渡すのか?
ポート番号が開いているとして、書き込めばいいのか? PHP でできるだろうか?

「exeからphpにデータを渡す」 (teratail)
https://teratail.com/questions/55331

プロセス間通信を調べてみるか。

「メッセージキューの使い方(CとPHPでプロセス間通信)」 (Linux Install Memo)
https://linux.yebisu.jp/memo/630

メッセージ・キューというのもあるのか。

メッセージ・キュー

とりあえず C# 側から調べてみよう。

「C# メッセージキューにメッセージを送信する」 (ITLAB51.COM)
http://www.itlab51.com/?p=4111

ウィンドウズの検索ボックスに「コンピューターの管理」と入れる。

[サービスとアプリケーション] - [メッセージ キュー] - [専用キュー]

今は空だが、ここに メッセージを置けるらしい。
あとで使ってみよう。

「C# メッセージキューからメッセージを受信する」 (ITLAB51.COM)
http://www.itlab51.com/?p=4173

先に メッセージ・キューを作成しないとダメみたいだ。

「C# メッセージキューに専用キューを作成する」 (ITLAB51.COM)
http://www.itlab51.com/?p=2322

よし、Windowsでは確認できた。

C# サンプルプログラム

using System;
using System.Messaging; // [References] - [Add Reference]

namespace MsgQueue
{
    /// <summary>
    /// キュー(メッセージ箱)に送り込んだ情報があるか確認する方法。
    /// (1) Windowsの検索ボックスに「コンピューターの管理」と入力。
    /// (2) [サービスとアプリケーション] - [メッセージ キュー] を開く。
    /// (3) [F5]キーで更新。
    /// </summary>
    class Program
    {
        public const string QUEUE_NAME = @".\Private$\testqueue";

        static void Main(string[] args)
        {
            for (;;)
            {
                Console.WriteLine(@"選べだぜ☆(^~^)
1   : メッセージ箱 作成
2   : メッセージ   送信
3   : メッセージ   受信
4   : メッセージ箱 削除
quit: 終了
");

                int category = 0;
                for (;;)
                {
                    string line = Console.ReadLine();
                    switch (line)
                    {
                        case "1": category = 1; goto gt_EndLoop1;
                        case "2": category = 2; goto gt_EndLoop1;
                        case "3": category = 3; goto gt_EndLoop1;
                        case "4": category = 4; goto gt_EndLoop1;
                        case "quit": goto gt_Quit;
                        default: break;
                    }
                }
                gt_EndLoop1:
                ;

                switch (category)
                {
                    case 1:
                        {
                            if (MessageQueue.Exists(QUEUE_NAME))
                            {
                                Console.WriteLine("キュー["+ QUEUE_NAME + "]は既存だぜ☆(^~^)");
                            }
                            else
                            {
                                // キュー名は、大文字で指定しても小文字になる
                                MessageQueue.Create(QUEUE_NAME);
                            }
                        }
                        break;
                    case 2:
                        {
                            MessageQueue mq = new MessageQueue((@".\Private$\testqueue"));
                            Message msg = new Message();
                            msg.Body = "テストメッセージだぜ☆(^▽^)";
                            msg.Label = "テストだぜ☆(^~^)";
                            mq.Send(msg);
                        }
                        break;
                    case 3:
                        {
                            MessageQueue mq = new MessageQueue((@".\Private$\testqueue"));
                            System.Messaging.Message msg = new System.Messaging.Message();
                            msg = mq.Receive();
                            msg.Formatter = new XmlMessageFormatter(new string[] { "System.String, mscorlib" });
                            Console.WriteLine(msg.Body.ToString());
                        }
                        break;
                    case 4:
                        {
                            if (MessageQueue.Exists(QUEUE_NAME))
                            {
                                MessageQueue.Delete(QUEUE_NAME);
                            }
                            else
                            {
                                Console.WriteLine("キュー[" + QUEUE_NAME + "]なんか無いぜ☆(^~^)");
                            }
                        }
                        break;
                }
            }
            gt_Quit:
            ;
        }
    }
}

Ubuntu でも試してみよう。

nano MsgQueue.cs
mcs MsgQueue.cs
MsgQueue.cs(2,14): error CS0234: The type or namespace name `Messaging' does not exist in the namespace `System'. Are you missing an assembly reference?
Compilation failed: 1 error(s), 0 warnings

どうやって System.Messaging の参照を追加するんだ?

「「○○○.dllを参照に追加します」の意味は?」 (DOBON.NET)
http://dobon.net/vb/dotnet/help/addreference.html

「/reference」 (MSDN)
https://msdn.microsoft.com/ja-jp/library/2b07fd84(v=vs.100).aspx

じゃあ、こんな感じでいいのか?

mcs /reference:messaging.dll MsgQueue.cs
error CS0006: Metadata file `messaging.dll' could not be found
Compilation failed: 1 error(s), 0 warnings

まあ、 .dll 無いよな。どうするのか……。

「System messaging dll missing?」 (stack overflow)
http://stackoverflow.com/questions/13409342/system-messaging-dll-missing

こうか。

mcs /reference:System.Messaging.dll MsgQueue.cs

行けた!?

./MsgQueue.exe
選べだぜ☆(^~^)
1   : メッセージ箱 作成
2   : メッセージ   送信
3   : メッセージ   受信
4   : メッセージ箱 削除
quit: 終了

1
選べだぜ☆(^~^)
1   : メッセージ箱 作成
2   : メッセージ   送信
3   : メッセージ   受信
4   : メッセージ箱 削除
quit: 終了

2
Insert: Mono.Messaging.RabbitMQ.MessagingContext

Unhandled Exception:
System.Messaging.MessageQueueException: Unable to connect to Queue: localhost\private$\testqueue, Error: None of the specified endpoints were reachable
  at System.Messaging.MessageQueue.Send (System.Object obj) <0x40f79d90 + 0x00227> in <filename unknown>:0
  at (wrapper remoting-invoke-with-check) System.Messaging.MessageQueue:Send (object)
  at MsgQueue.Program.Main (System.String[] args) <0x40f46d50 + 0x00233> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Messaging.MessageQueueException: Unable to connect to Queue: localhost\private$\testqueue, Error: None of the specified endpoints were reachable
  at System.Messaging.MessageQueue.Send (System.Object obj) <0x40f79d90 + 0x00227> in <filename unknown>:0
  at (wrapper remoting-invoke-with-check) System.Messaging.MessageQueue:Send (object)
  at MsgQueue.Program.Main (System.String[] args) <0x40f46d50 + 0x00233> in <filename unknown>:0

なんのこっちゃ~。

「None of the specified endpoints were reachable」 (stack overflow)
http://stackoverflow.com/questions/32432018/none-of-the-specified-endpoints-were-reachable

シングルトンで解決するのか?

「Linux のメッセージキュー (IPC)」 (楽吾楽, Repeat myself)
http://blogs.yahoo.co.jp/ichi0346/34314386.html

うーむ、エラーが出るぜ。

cat /proc/sys/fs/mqueue/msg_max
10
cat /proc/sys/fs/mqueue/msgsize_max
8192
cat /proc/sys/fs/mqueue/queues_max
256

Qiitaのゲートウェイがタイムアウトした。記事を変えよう。

<その2>へ

8
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11