Moon? Shadow! - Misc Memo

Moon? Shadow!の記事にならない雑多なメモなのですー>ω<

  • Moon? Shadow! - 月影の本ブログなのですー>ω<(ソースコードを紛失したため更新停止中です)
  • Github kagamilove0707 - Githubのアカウントなのですー>ω<

随伴がモテないのはどう考えてもモナドが悪い!(モナドとコモナドの関係が分かる話)

この記事が対象としている読者

  • モナドって何となく聞いたことがある人
  • 圏論よく分かんないけど、圏の定義(対象と射と合成と恒等射と……)みたいなことは聞いたことがある人

要するに、モヤモヤしてても問題ないのですけれど、最低限の知識くらいはあった方がいいってことなのですー>ω<

また、この記事は深淵なHaskellプログラマのみが書くことを許されると言われるモナドチュートリアルではないのでそういったものを期待されていたら、ごめんなさいなのです><

続きを読む

zshで、readでn文字ずつ読み込みますです

zshreadで入力を受け付けることができますですー>ω<

$ read line
hello, world
$ echo $line
hello, world

このreadにはいくつかのオプションがありますでして、その中の一つに-kというものがありますです。これは、k文字の入力を受け取るということで、このように使えますです。

$ while read -k 5 five; do echo "-> $five"; done
xxxx-> xxxx
hello-> hello
^C
$

ちょうど5文字入力したところで反応してとても面白いのですー>ω<

しかし、このread -kには重大な問題がありますです。それは、このままではパイプラインやリダイレクトを使って入力を指定したとしても、標準入力へ入力を受け付けに行ってしまうのです(`・ω・′)

$ cat hello.txt
hello, world
$ cat hello.txt | while read -k 5 five; do echo "-> $five"; done

諸事情(わたしの場合bf.zsh)で、n文字ずつ文字列を受け取らなくてはいけない場合、これでは大変困ったことになりますです。

()で囲って別プロセスにしたり、別ファイルに記述したりしても上手くいかなかったので半ば諦めていたのですが……
man zshbuiltinsreadを眺めていたら、-uというオプションを見付けたのですー>ω<

どのファイルデスクリプタを入力に使用するかを明示的に指定するオプションなのですが、これに標準入力のファイルデスクリプタである0を指定したところ、上手くいったのです>ω<

$ cat hello.txt | while read -n0 -k5 five; do echo "-> $five"; done
hello
, wor
ld
$

ちなみに、このオプションを指定すると-kオプションのみの場合と違ってキーを押した瞬間に反応したりはしなくなる様子ですので、注意して欲しいのですー>ω<

(ところで、zshの組み込みコマンドでファイルをopenしてファイルディスクリプタを取得するにはどうしたらいいのです?? 現状は困らないのですけれど)

最後に、この話に教訓を残すなら「迷わずにmanを見ろ」ということです。ありがとうございましたのですー>ω<

Vimで、開いているファイルを再読み込み

filetypeを設定ためのコメントを追加したときなど、ファイルを再読み込みしたいときがありますです

そんなときは、

:e %

で、再読み込みできますですー>ω< %は現在のバッファのファイル名になっているのです

追記

と、思っていたのですが、実は、

:e

だけでも再読み込みできるみたいなのでしたー

もっと良い方法がありましたら教えていただきたいのですー>ω<

Ubuntu 13.10で、zshのmanページが見れないことの対処法なのですー>ω<

Ubuntu13.10のバグで、zshのmanページが見れなくなっていますです。

$ man zsh
zsh というマニュアルはありません

Bug #1242108 “all zsh manpages are missing” : Bugs : “zsh” package : Ubuntu

これはパッケージにzshのmanページを含めていなかったことが原因のようなのですが、ごちゃごちゃしていて未だに解決していないのです(もしかしたら、14.04では直っているかもしれませんが、現時点で上に上げたページの議論がcloseしていないのでどうなんだろうな、って感じです)(′・ω・`)

info zshという手もあるのですが、やっぱりLinuxのマニュアルといったらmanなので、やはりmanで見たいものです。なので、今回は仕方ないので、手動でzshのmanをインストールすることにしますです。

$ cd ~/Downloads
$ mkdir zsh-doc && cd $_
$ wget http://downloads.sourceforge.net/project/zsh/zsh/5.0.2/zsh-5.0.2.tar.bz2
$ tar -xvf zsh-5.0.2.tar.bz2
$ cd zsh-5.0.2/Doc
$ ls -p *.1
zsh.1     zshbuiltins.1  zshcompctl.1  zshcompwid.1  zshexpn.1  zshmodules.1  zshparam.1    zshtcpsys.1   zshzle.1
zshall.1  zshcalsys.1    zshcompsys.1  zshcontrib.1  zshmisc.1  zshoptions.1  zshroadmap.1  zshzftpsys.1

manファイルを見つけたので、これを適当なディレクトリにコピーして、そこを環境変数MANPATHに加えますです

$ mkdir -p ~/man/man1
$ cp *.1 ~/man/man1

として、適当なエディターで.zshenvを開いて、

export MANPATH=$HOME/man:

を追加しますです。ポイントは、zshのmanファイル(拡張子が1で終わっているもの)を~/man/man1にコピーしたのに対し、環境変数MANPATHに設定したパスは$HOME/manであるという点です。これは、manのディレクトリのレイアウトに合わせているからなのです。
また。MANPATHの最後に:を追加していますですが、これを忘れるとシステムのmanを参照できなくなりますですので注意ですー>ω<

zsh文法帳なのですー>ω<

moonline.zshというものを作っていますですので、zshの文法を理解していなければいけないのですが、わたしはまだzshを使い始めて一週間にもならない未熟者なのですので、学習したことをメモしておきたいと思いますですー>ω<

色々と偏っているかもしれませんですし、(恐らく永遠に)書きかけの記事なので、あまりあてにしない方がいいかもしれないのですー>ω<

また、シェルスクリプトzshも初心者なので、どこもかしこも間違っていそうな気がしていますです。なので、間違いを指摘していただけると、わたしとしては至極嬉しい限りなのです!

コメント

# コメントは # から始めますですー>ω<
# ちなみに、 下記のオプションを設定しないと対話シェル中ではコメントが有効にならないので注意なのです
setopt interactive_comments

コマンドの実行

# 普段、端末で行なうのと同じです
mkdir test # mkdir はディレクトリを作るコマンドです (MaKe DIRectoryの略だと思われます)
cd test    # cd はディレクトリを移動するコマンドです (Change Directoryの略だったと思いますです)

# ; で区切って複数実行できますです
touch test.txt; ls # touch はファイルの編集時刻を更新するコマンドです。ファイルが無い場合は作成する、という機能もありますです
                   # ls はディレクトリのファイルなどの一覧を表示するコマンドです

# && で、左のコマンドが正常に行なわれたら、右のコマンドを実行する、といったことができますです
mkdir test2 && cd test2

出力

# 出力には echo コマンドを使いますです
echo "Hello World"

# 改行なしにする場合は、 -n オプションを付けますです
echo -n "Hello World"

変数

# 代入(連想配列以外なら宣言は必要ないのです)
# 変数名と = の間に、空白を入れないことが大切なのです
x=1

# 複数使う場合は、空白区切りで並べられますです(別に改行で区切っても問題ないです)
y=2 z=3

# 初期化したい場合は、左辺に何も書かないのです(単に変数名だけだと、その名前のコマンドと解釈されてしまいますです)
w=

# 参照は$を付けますです
echo $x #=> 1

# 空白を含む場合は、 "" で囲うのです
x="Hello World"
echo $x #=> Hello World

# 変数から変数への代入は、参照するのと同様のイメージなのです
y=$x
echo $y #=> Hello World

# "" の中でも変数を展開できるのです
echo "$x - こんにちは世界" #=> Hello World - こんにちは世界

# ただし、 '' の中では展開されないのです
echo '$x' #=> $x

# 存在しない変数は "" (長さゼロの文字列)として扱われるのです(エラーが出ない)
echo $xxx #=> (何も表示されない)

# 展開するとき、どこまでが変数名か分からなくなるなら、 {} で変数名を囲うのです
echo "$xWideWeb"   #=> (何も表示されないのです。なぜなら、存在しない $xWideWeb という変数を参照しているからなのです)
echo "${x}WideWeb" #=> Hello WorldWideWeb

配列

# () で囲って、要素を空白で区切りますです
xs=(1 3 5)

# 要素の参照は、1から始まりますです
echo $xs[1] #=> 1
echo $xs[2] #=> 3
echo $xs[3] #=> 5

# 要素に代入することもできますです
xs[1]=2
echo $xs[1] #=> 2

# 配列の入った変数をそのまま参照すると、空白区切りの文字列となりますです
echo $xs #=> 2 3 5

# 要素数は、 $# で参照しますです(冷静に考えると、ここでの # はコメントとして解釈されないのですね。不思議です(`・ω・′))
echo $#xs #=> 3

# 要素の追加には += を使いますです。この場合は末尾に追加されるのです
xs+=(7)
echo $xs  #=> 2 3 5 7
echo $#xs #=> 4

# 配列を別の変数に代入するときは、()で囲むのです
# ちなみに、要素に空白を含むものがあっても問題ないのです
ys=($xs)
echo $ys #=> 2 3 5 7

# さっきのはRubyやPythonなどのようにオブジェクトを参照しているのではなく、コピーを取っているので、要素に代入しても一方に反映される、といったことはないのです
ys[1]=1
echo $ys #=> 1 3 5 7
echo $xs #=> 2 3 5 7

# 配列のループには、 for文(これはzshに組み込まれたものなので、コマンドではなく文法なのだと思いますです)を使いますですー>ω<
# これは、pythonで言うfor in文、PHPのforeach文のようなものなのではないかと思いますです
for x in $xs; do
  # x に各要素が代入されていますです
  echo -n "${x}x"
done
#=> 2x3x5x7x

# どうしてもインデクッスでループをしたいのなら、次のように書くこともできますです
# (ただし、あまりこの書き方はしないような気がしますです)
for ((i = 1; i <= $#xs; i++)); do
  echo "$i --> $xs[$i]"
done
#=> 1 --> 2
#=> 2 --> 3
#=> 3 --> 5
#=> 4 --> 7

関数

# zshの関数の定義方法は、2つありますです

# 1つは、function文を使う方法です
function fn1() {
  # 引数は $1,$2...$9 で取得することができますです
  echo "1 --> $1"
  echo "2 --> $2"
}

# 呼び出しは、コマンドのようになりますです
fn1 a b
#=> 1 --> a
#=> 2 --> b
fn xxx yyy
#=> 1 --> xxx
#=> 2 --> yyy

# もう1つは、functionを省略した形です。こちらの方が(何となくですけど)伝統的なような気がしていますです
fn2() {
  echo fn2
}
fn2 #=> fn2

# この2つの違いはよく分からないのです(′・ω・`)
# どなたか教えて下さると幸いです
# 今回は、省略した形の方が短かく書けるし、そうしないとVimのインデントが上手く働いてくらなかったのでそちらを採用しますです

# 関数の中で変数を使うときに、グローバル変数を壊したくないのなら、 local で宣言するのです
x="global variable" y="global variable"
fn3() {
  # こんな風に
  local x
  x="local variable"
  echo "x is $x" #=> x is local variable

  # 宣言と代入を同時に行なうこともできますです
  local y="local variable"
  echo "y is $y" #=> y is local variable

  # 複数の変数を同時に宣言することもできますです
  # 初期値はあっても無くても問題ないのです
  local z w=local

  # ただし local の場合、配列は同時に代入することができないのです
  # local xs=(1 2 3) # これはエラーになるのです
  # この場合、宣言と代入を2回に分けて行なうといいのです
  local -a xs # -a オプションは、配列の変数を宣言していることを表わしますです。今回はすぐに代入してしまうので関係ありませんが、空の配列として初期化されますです
  xs=(1 2 3)
  echo $xs  #=> 1 2 3
  echo $#xs #=> 3
}
# localで宣言しているので、変数は上書きされないのです
fn3 # fn3の呼び出し
echo "x is $x. y is $y too"
#=> x is global variable, y is global variable too

# 可変長引数は、$* か $@ という特殊な変数を使って参照できますです。また、引数の個数は $# なのです
# fn4 は与えられた引数を全て表示する関数
fn4() {
  local i arg # for文で使うループ変数も local で宣言しておかないと、グローバルな変数として扱われてしまうので注意です
  for ((i = 1; i <= $#; i++)); do
    echo "$i --> $*[$i] $@[$i]"
  done
}

# fn4を呼び出してみますです。$@と$*が "この場合は" 違わないことが分かりますです
fn4 1 a "Hello World"
#=> 1 --> 1 1
#=> 2 --> a a
#=> 3 --> Hello World Hello World

# もう1つ実験してみますです

# $* と $@ で引数を展開して、fn4 に渡す関数
fn5() {
  echo '$*'; fn4 $*
  echo '$@'; fn4 $@
}
fn5 1 a "Hello World"
#=> $*
#=> 1 --> 1 1
#=> 2 --> a a
#=> 3 --> Hello World Hello World
#=> $@
#=> 1 --> 1 1
#=> 2 --> a a
#=> 3 --> Hello World Hello World

# $* と $@ は、配列として参照する場合には違いはないのです
# では、どんなときに違いが表れるのかというと、""に囲んで展開したときに変化があるのです

# fn6 は与えられた引数を "$*" で fn4 に渡す関数
fn6() {
  echo '"$*"'; fn4 "$*"
}

# fn7 は与えられた引数を "$@" で fn4 に渡す関数
fn7() {
  echo '"$@"'; fn4 "$@"
}

# この fn6 と fn7 を使うと、"$*" と "$@" の違いが顕著に表れますです

fn6 1 a "Hello World"
#=> "$*"
#=> 1 --> 1 a Hello World
fn7 1 a "Hello World"
#=> "$@"
#=> 1 --> 1 1
#=> 2 --> a a
#=> 3 --> Hello World Hello World

# "$*" のときは1つのパラメーターとして、 "$@" のときは複数のパラメーターとして展開されていますです!

(書きかけ…。まだまだ書きたいことはあるのです…。文字列関連とか、ともかく色々)

はてなブログを始めてみたのですー>ω<

ブラウザでささっと更新できるものが欲しかったので、はてなブログを始めることにしましたのですー>ω<

とは言っても、このブログに書くことはブログの名前「Moon? Shadow! - Misc Memo」にもある通り、雑多なメモの集まりとなる予定なのです。その点では、Github Pagesの方のブログと区別していきたいと思っていますです。

要するに、健忘録。

というわけで、よろしくなのですー>ω<


CC0
To the extent possible under law, TSUKIKAGE Osana has waived all copyright and related or neighboring rights to Moon? Shadow! - Misc Memo. This work is published from: 日本.