君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

シェルで文字列を比較したときに、[: =: unary operator expected :というエラーがでる

f:id:karoten512:20180119002642j:plain

いきさつ

空行を検出するスクリプトを書いていた

古池や

蛙飛び込む
水の音

をシェルに読み込ませ、空行があったときに

「空行があるよ」というスクリプトを書いた。

※ 実際の処理を簡略化してます

#!/bin/bash
while read line
do
  if [ $line = '' ]; then
    echo '空行があるよ'
  fi  
done < line.txt

しかしうごかないんだなこれが

test.sh: line 4: [: =: unary operator expected

というエラーがでる。

どこでエラーが置きているかわからないので、

#!/bin/bash
while read line
do
  echo $line # ここで出力する
  if [ $line = '' ]; then
    echo '空行があるよ'
  fi  
done < line.txt

echo で毎行出力してみる。

古池や

test.sh: line 5: [: =: unary operator expected
蛙飛び込む
水の音

どうやら空行を読み込んだ時に起きているエラーのようだ。

調べてみた

fluidx.exblog.jp

変数に格納されている文字列比較において、 文字列の比較は文字列と行う必要があるところを、 文字列と何かわからない型の変数を比較してしまっているので、 このようなエラーが発生するらしい。

空行は「文字列かわからない型」なのか…?

ちょっとそこは釈然としない。

対処

#!/bin/bash
while read line
do
  if [ "$line" = '' ]; then
    echo '空行があるよ'
  fi  
done < line.txt

$lineを""でかこむ。文字列にキャストしている感じなのかな。

結果

空行があるよ

動いた。

シェルは独特。でもサッとかけるから便利。

環境を選ばないしねぇ。

最強のポータビリティ言語である。

1つのファイルを複数のディレクトリにコピーしたい〜UNIXコマンド:xargsとcpについて〜

f:id:karoten512:20180117121818p:plain

1つのファイルを複数のディレクトリにコピーしたい

dir1, dir2, dir3にfileをコピーしてばらまきたい。

結論

echo dir1 dir2 dir3 | xargs -n 1 cp -v file

読み解いてみる

xargs

とは

標準出力をコマンドライン引数に変えるコマンド。

今回の例で言えば、echoによって出力される標準出力を、

コマンドライン引数としてcpに渡している。

-nオプションとは

数字をすこしいじってみた。

$ echo dir1 dir2 dir3 | xargs -n 1
dir1
dir2
dir3
$ echo dir1 dir2 dir3 | xargs -n 2
dir1 dir2
dir3
$ echo dir1 dir2 dir3 | xargs -n 3
dir1 dir2 dir3

なるほど。

引数をいくつづつ渡すかを指定するコマンドなのね。

cpとは

概要

ファイルをコピーするコマンド。

-vオプションとは

オプション有り。

$ cp -v fileA fileB
flieA -> fileB

オプション無し。

$ cp -v fileA fileB

何も言わねえ。

まとめ

xargs、

コマンドライン引数しかうけとらないコマンドに、

標準出力をわたしたい時に活躍するみたい。

面白いな。

unixコマンドは1つ1つの機能が小さいので、汎用性が高い。

組み合わせて使って楽しい。

いろいろ覚えていこう。

参考

orebibou.com

社長の家ですき焼きしたら、破壊神シヴァが現れた話。

f:id:karoten512:20180117195749j:plain

いきさつ

今年の冬、linuxの資格であるLPICのレベル1を取得した。

資格のレベル自体は大したことないのだけれど、

社長「お祝い何がいい?報酬とは別に、どこかお店つれってったげる」

社長「みんなで高いお店行こー!」

私「それなら」

私「すき焼きやりましょう」

私「社長の家で」

上司「それいいね!」

社長「それいいね!」

というわけで社長の家ですき焼きをすることになりました。

参加者

  • 社長

  • 社長の奥さん

  • 娘さん (2)

  • かろてん(私)

  • 私の上司

  • 社長宅に居候しているポルトガル人 ジェロ

  • ジェロの奥さん

謎の布陣ですき焼きをすることになった。

破壊神、がいた

社長の家につくと、

娘さんが大暴れしていた。

破壊神。

その言葉がぴったりだった。

社長が洗濯物をたたむ。

壊す

社長がお絵かき帳を渡す。

切り刻みまくる

社長が完成したパズルを渡す。

すべて蹴散らす

やばい。

創造と破壊は表裏一体とはよく言うが、

この子は破壊しかしない。

もはや社長の娘(2)ではない。

シヴァだ。

この子は破壊神シヴァ(2)だ。

社長が叫んだ。

社長「かろてん!シヴァをみててくれ!」

私の役割は、シヴァのおもりだった

このお守りで、

ボーナスの額が決まると言っても過言ではない。

私は全力でシヴァのお守りをすることにした。

私は役に立たない男であった

私の親戚には小さい子がいない。

いとこはみんな年上だ。

だから小さい子の扱い方を1ミリもしらなかった。

私がしたのは、

破壊活動の幇助と、

創造活動への啓蒙だ。

ハサミを渡す。

クレヨンを渡す。

のりを渡す。

私の活躍により、

破壊神シヴァ(2)は、

創造神ブラフマー(2)へ、

ありえない進化を遂げようとしていた。

きりきざまれた紙。

あり得ない配色に彩られた画用紙。

それが創造神の周りに、積もり積もっていく。

つまり、

破壊活動から破壊的創造活動に切り替わっただけで、

惨状は変わらなかった。

社長「かろてんだめだ!君は子守むいてないよ!」

今年のボーナスが、消えた。

私は迷子になった

すき焼きは美味しかった。

ガブガブ酒をのみ、

そろそろ帰ろうという時になって

上司と家に帰ることにした。

しかし、私は帰れなかった。

正確に言うと、

酒により極度に下がった空間把握能力で

空間が歪み、

最寄り駅の方向すらわからなくなった。

もともと私は道を覚えるのが得意ではない。

ポルトガル人はそのことを知っていて、

私のことをいつも、

「lost child(迷子)」

と呼んでいる。

私は助けをもとめた。電話で。

私「I’m completely lost child」

社長「OK. Don’t move」

私の記憶は、そこで途絶えている。

目が覚めると、そこは

社長の家だった。

社長はすでに出勤していた。

私は、

ポルトガル人におこされ、

ポルトガル人の奥さんにヨーグルトをもらい、

無言で食べた。

ポルトガル人といっしょに電車に乗り、

ポルトガル人といっしょに改札を出、

ポルトガル人といっしょに出勤した。

今日も

仕事頑張ろう。

curlからフォームデータを贈りたい時のオプションについて

curlの使い所

  • スクリプトから直接URLを叩きたい時
  • パラメータを変えてたくさんのリクエストを贈りたい時

こんなときはcurlが便利。

フォームデータを投げたいときは-data, -dオプション

curl --data form_name=form_value http://www.example.com/

POSTでフォームデータを送る。

なお、-Xでメソッド指定ができるので、上記は下記と同じになります。

curl -X POST --data form_name=form_value http://www.example.com/

盗み聞きしてみた(コンテナ上のnginxプロセスと、ホスト間の通信パケットをtcpdumpでキャプチャしてみた〜CoreOS toolboxを使ってみる〜)

f:id:karoten512:20180112224543p:plain

パケットキャプチャとは

サーバさんたちがどんなおはなしをしているのか、

ぬすみぎきすることだよ(白目)

いきさつ

ホスト間とコンテナ上のnginxがどういう通信をしているのか気になった。

普通のサーバへの通信と変わらないのかな。

こういうときは実験だ。

盗み聞きまでの手順

nginxコンテナを起動

$ docker pull nginx:latest
$ docker run --name nginx_test -d -p 8080:80 nginx:latest

CoreOSにtcpdumpを入れる

qiita.com

CoreOS toolboxを使用すると、tcpdumpが使えるみたい。

盗み聞きする

Docker上で走っているコンテナとホスト間は、

docker0という仮想ブリッジでつながっている。

(ホスト上でifconfigをするとdocker0があることがわかるよ)

なのでdocker0を盗みぎきするNICに設定。

$ tcpdump -i docker0

結果

14:06:21.082183 IP 172.17.8.1.55248 > 172.18.0.6.http: Flags [S], seq 584948487, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1315360133 ecr 0,sackOK,eol], length 0
14:06:21.082237 IP 172.18.0.6.http > 172.17.8.1.55248: Flags [S.], seq 636172623, ack 584948488, win 28960, options [mss 1460,sackOK,TS val 3302158741 ecr 1315360133,nop,wscale 7], length 0
14:06:21.083531 IP 172.17.8.1.55248 > 172.18.0.6.http: Flags [.], ack 1, win 4117, options [nop,nop,TS val 1315360133 ecr 3302158741], length 0
14:06:21.083662 IP 172.17.8.1.55248 > 172.18.0.6.http: Flags [P.], seq 1:587, ack 1, win 4117, options [nop,nop,TS val 1315360134 ecr 3302158741], length 586: HTTP: GET / HTTP/1.1
14:06:21.083677 IP 172.18.0.6.http > 172.17.8.1.55248: Flags [.], ack 587, win 236, options [nop,nop,TS val 3302158743 ecr 1315360134], length 0
14:06:21.083835 IP 172.18.0.6.http > 172.17.8.1.55248: Flags [P.], seq 1:181, ack 587, win 236, options [nop,nop,TS val 3302158743 ecr 1315360134], length 180: HTTP: HTTP/1.1 304 Not Modified
14:06:21.084186 IP 172.17.8.1.55248 > 172.18.0.6.http: Flags [.], ack 181, win 4112, options [nop,nop,TS val 1315360134 ecr 3302158743], length 0

ちょっと見てみる。

パケット解析

3 way hand shake

サーバ同士でお話するときはいきなり話しかけない。

「ちょっとお話しませんか?」

「いいですよ。こっちもちょっと話していいですか?」

「いいですよ」

という紳士的なやり取りをして、はじめてお話が始まる。

それを

3 way hand shake

という。

↓ その痕跡がこれ

(1)IP 172.17.8.1.55248 > 172.18.0.6.http: Flags [S]
(2)IP 172.18.0.6.http > 172.17.8.1.55248: Flags [S.], ack
(3)IP 172.17.8.1.55248 > 172.18.0.6.http: Flags [.], ack

ここで大事なのはFlags[S]ack

(1)接続元が接続先に対して「ちょっとお話しませんか?」と聞いている

Flags [S]は、

SYN(コネクション確立要求)の先頭文字。

相手に対して、

「ちょっとお話しませんか?」と聞いてる感じ。

(2)接続先が接続元へ「いいですよ。私も話していいですか?」と聞いている

ack が「いいですよ」

S が「私も話していいですか?」

(3)接続元が接続先へ「いいですよ」いってる。

ack が「いいですよ」

この3つの過程を経て、ようやく通信ができるようになる。

GETリクエス

IP 172.17.8.1.55248 > 172.18.0.6.http: (省略) HTTP: GET / HTTP/1.1

/ ディレクトリへアクセス。

確認応答

IP 172.18.0.6.http > 172.17.8.1.55248: Flags [.], ack 587

ここは勉強不足で、どこらへんが確認応答なのかわかっていない…

レスポンス

172.18.0.6.http > 172.17.8.1.55248: (省略) HTTP: HTTP/1.1 304 Not Modified

何度か通信していたので、取得したコンテンツが更新されていないことが確認できた。

まとめ

コンテナ - ホスト間の通信は、

普通のhttp通信と同じようにみえる。

違うのは、docker0という仮想ブリッジを通した通信だ、ということくらいかな。

CoreOS toolboxに入れない〜Failed to allocate scope: Unit core-fedora-latest.scope already exists.〜

f:id:karoten512:20180112225511p:plain

CoreOS toolbox使ってたらこんなエラーがでた

CoreOSでtoolboxコンテナを使い、

Ctrl-wで無理やりコンテナを抜けた。

そしていつものようにtoolboxを起動したら、

$ /usr/bin/toolbox

らこんなエラーがでた。

Failed to allocate scope: Unit core-fedora-latest.scope already exists.

困ったぞ。

stack overflowの記事

github.com

Fedra25だと起こる問題みたい。

対処

dockerホスト上で、以下のコマンド実行。

$ echo "TOOLBOX_DOCKER_TAG=24" >>$HOME/.toolboxrc

その上でもいちど

$ /usr/bin/toolbox

いつものtoolboxコンテナに入れた。

Dockerでたてたコンテナにtelnet-serverを入れて、telnetでコンテナ間通信ができるようにしてみた

f:id:karoten512:20180110003655p:plain

いきさつ

networkやセキュリティ、telnetデーモンを叩き起こすxintedの勉強がてらやってみた。

手順

0. 準備

0-1. telnet-server用のコンテナを走らせる

$ docker pull centos:centos7
$ docker run --privileged -d --name centos_test centos:centos7 /sbin/init

なお、telnet-serverコンテナでは、

後程systemdを用いてサービスを走らせるので、

--privilegedと/sbin/initが必要になってくる。

qiita.com

0-2 telnet-client用のコンテナを走らせる

$ docker run -d --name telnet-client centos:centos7

1. telnet-serverコンテナの設定

1-1. telnet-serverのinstall

$ docker exec -it telnet-server /bin/bash
# yum -y install telnet-server

1-2. リモートホストからのアクセス制御の設定をする

他のサーバからのアクセスを制御します。

すべてのhost/すべてのサービスからのアクセスを拒否します。

# echo 'ALL: ALL' >> /etc/hosts.deny

特定のサービス/特定のホストからのアクセスを許可します。

# echo 'in.telnetd: 172.18.0.5' >> /etc/hosts.allow

telnetデーモンに対して、172.18.0.5からアクセスがあった場合は許可します。

なお、172.18.0.5はtelnet-clientコンテナのipアドレス

1-3. xinetdの設定

# vi /etc/xinetd.d/telnet

以下を追記します。

service telnet
{
    flags       = REUSE
    socket_type = stream
    wait        = no
    user        = root
    server      = /usr/sbin/in.telnetd
    log_on_failure  += USERID
    disable     = no
}

2. telnet-serverの起動

# systemctl status telnet.socket

3. telnet接続用のuserを作成する

# useradd telnet-user
# passwd telnet-user
Changing password for user telnet-user.
New password:
Retype new password: 

4. telnet-clinentコンテナの設定

4-1. telnet-clinentのinstallをする

$ docker exec -it telnet-client /bin/bash
# yum install -y telnet

4-2. 接続

いちおう、サーバ側のポートが空いていることを確認してみる。

$ nmap -sV -PE -p 23 172.18.0.4
Starting Nmap 6.40 ( http://nmap.org ) at 2018-01-09 16:00 UTC
Nmap scan report for 172.18.0.4
Host is up (0.000039s latency).
PORT   STATE SERVICE VERSION
23/tcp open  telnet  Linux telnetd

あいてた。

$ telnet 172.18.0.4 23
Trying 172.18.0.4...
Connected to 172.18.0.4.
Escape character is '^]'.

Kernel 4.14.11-coreos on an x86_64
f71734bf26ca login: telnet-user
Password: 
Last login: Tue Jan  9 16:07:51 from 172.18.0.5

入れた!

感想

コンテナからコンテナにtelnetログインするだけでそれなりの作業量となる。

色々勉強になった。

参考

kajuhome.com