最近の更新

関連


その他いろいろ

MODxでつくる! 最強のCMSサイト カバー
MODxでつくる! 最強のCMSサイト

はやくMODx 2.0でないかなあ

長い作業をしているシェルスクリプトをうっかりCtrl-Cしてしまって悲しい思いをすることはよくあります。

簡単な対処法としてSIGINTを無視するtrap '' 2をスクリプトに加えるというものがありますが、
常に無視されるというのも本当に終了させたいときに手間なものです。(Ctrl-Zでサスペンドしてkill -9など)

そこで、一度Ctrl-Cを押すと本当に終了して良いか質問した上で終了/続行するスクリプトを使ってみます。
(1/26 複数のシグナルを指定すると狂うバグがあったので修正しました)

以下、sigconfirm.sh

#!/bin/bash

# trap handler
function traphandler() {
  # disable SIG* inside this handler
  trap '' $@
  echo -n "Are you sure to quit? [y/n] "
  read c
  if [ "${c/Y/y}x" == 'yx' ]; then echo 'quit'; exit 1; fi
  echo 'continue.'
  trap "traphandler $*" $@
}

# register trap handler for SIG*
trap "traphandler $*" $@

これを自分のスクリプトでsourceすると、

#!/bin/bash

source sigconfirm.sh 2

while :; do echo ':'; sleep 1; done

(引数2は補足するシグナルの種類。source sigconfirm.h 1 2 3 15 のように複数指定できます)

以下のようになります。

$ ./testsigconfirm.sh
:
:
^CAre you sure to quit? [y/n] n
:
:
^CAre you sure to quit? [y/n] y
$

普通にtrapした場合、trap内部の処理中にまたCtrl-Cが押されると終了してしまうのですが、ここではハンドラの内部ではSIGINTを無視するように設定しているため、Ctrl-Cをうっかり連打してしまっても落としてしまうことがありません。

シェルを使っているとテンポラリのディレクトリやバックアップ用tar.gzの作成などで日付を入力したくなることがあります。

一々時計を見て入力するのは面倒で非効率。ここは自動的に入力させたい。
そしてzshの強力な履歴補完を考えると、日付文字列そのままを挿入するより、

$(date +%Y%m%d)

を入れてくれた方が再利用できて助かります。

以下の数行を.zshrcにコピペしましょう。F5でYYYYmmddに展開されるdateコマンド置換が挿入されます。


# insert `date` for YYYYMMDD on F5
function insert_date {
  LBUFFER=$LBUFFER'$(date +%Y%m%d)'
}
zle -N insert_date
bindkey '^[[15~' insert_date

zshでファンクションキーをbindkeyする方法が分からなくて困りましたが、普通にシェル上でC-V F5と押せば^[[15~とでたので、それを使ってみました。

zshで

cd -[TAB]

とすると、setopt auto_pushdしていた場合は過去にいたディレクトリが

~% cd -
0 -- /home/**/work/dotfiles/.vim  (一番昔)
1 -- /home/**/work/dotfiles
2 -- /home/**/work                (直近)

のように表示されます。しかし、このままタブを押し続けていくと、最も昔にいたディレクトリから順次選択れていくのはやや直感的ではありません。できれば直近にいたディレクトリを優先してリストアップしてほしい。

zstyleのヘルプを見ても’completion:complete:cd:*’でリストを逆順にする方法が分からず、途方に暮れていたところ…

Zsh Workshop: The Directory Stackを見ていて

cd +[TAB]

が目的の動作だったと閃きました。

~% cd +
1 -- /home/**/work
2 -- /home/**/work/dotfiles
3 -- /home/**/work/dotfiles/.vim

ただUS配列では+はシフトが必要で若干面倒なので、setopt pushd_minusとして+と-の意味を入れ替えると良さそうです。

しかしリスト/メニューを逆順にするzstyleが見つからないのは結構問題です。file-sortに関しては’reverse’というオプションがあるらしいですが、それ以外は候補を自分で生成するしかないのでしょうか。

以前書いたC++がPythonより重い…でソースコードを載せると言いつつ載せて無かったので、引っ張り出してきました。

ptest_regex.zip をダウンロード

昔のことで記憶が曖昧ですが、たしかC++, Python, 生grep (追記: C#も)で

データセット 実験1 実験2 実験3
ソースコード int.*\( ^.*$ ^.*int.*$
のち^.*\(.*$
のち^.*\).*$
(英文?)和文 は.*。 ^.*$ ^.*は.*$
のち^.*た.*$
のち^.*。.*$

をそれぞれ試しています。多分。

用いたデータセットや結果は過去のエントリを参照してください。

勿論「C++よりPythonが全面的に速い」「C++とPythonで同じアルゴリズムを実装すると後者が速い」ということが言いたいのではありません。(そしてそれは多分言えないと思う)

適当に使えそうな/気軽に使ってしまうライブラリ(C++ではboost, ICU、Pythonでは標準のエンコーディング変換関数とre)を自然に使ってみるだけだとPythonの方が早いこともあるらしい、という驚きと悲しみをちょっと記録しただけです。

「自然に」が自分の中では結構大事で、無理して良いなら当然自由度の高い低レベルな言語が一番チューニング出来る可能性がある、でもパラメタが多すぎて難しい。
まあPythonは標準ライブラリを使っているため、ちょっとチューニングしたいと思ったときに改変がやや面倒なのに対し、C++は標準ライブラリ以外を使っている(勿論stlも使ってますが)のでその辺は楽、という点はやや不公平ではあるかもしれませんが。

C++を自然に使ってより早い結果が得られる方法があれば、教えてもらえると嬉しいです。xpressiveとか使ったこと無いけどどうなんんでしょう。

追記
忘れていましたがPython vs C++ vs C# @ 7bitでC#版も書いていたらしい。記憶にない… でもソースもあったので追加しておきました。

昨日、zshでsudoや|を無視して履歴から補完する設定を紹介しましたが、
これをC-P/C-Nにしてしまうと、例えば本当にsudo付きだったldconfigを補完する目的で

sudo l(補完)

とすると肝心の物が引っかからず、

sudo ls ..

などと補完されてしまうのが時々鬱陶しいので、Alt-P / Alt-Nに設定してみました。

zle -N smart-search-history-backward
bindkey '^[p' smart-search-history-backward
zle -N smart-search-history-forward
bindkey '^[n' smart-search-history-forward

この辺は好みに応じてC-P/Nの場合はパイプだけ無視して補完、M-P/Nはsudoも含めて無視して補完、などとすると良いかもしれません。

ちょっと嵌ったのが、bindkeyのキーでAlt(Meta)を指定するには\M-pとか^[pとかありますが、これは大文字小文字センシティブらしいこと。Ctrlでは気にする必要無かったので全部大文字にしてたら引っかかりました。

ちなみに^[は本当のC-[ではなく、単にハットと開始カギ括弧です。

zshでhistory-beginning-search-backwardをCtrl-Pなどに割り当て、入力したところまでマッチするように履歴から補完するように設定している方は多いと思います。

しかし、プロンプト先頭からカーソル位置までが検索対象となってしまうため、先にsudoを入れたり、パイプの途中から補完するといったことはできません。

そこで、現在のプロンプト入力からいくつか指定のパターンを除外した上で補完できるようなzleのウィジェットを書いてみました。

履歴に

sudo apt-get update
make
make install
ldconfig
less

があったとして、普通は

sudo m(補完)

としても何も補完されませんが、この設定を用いると

sudo make install => sudo make

のように補完してくれます。

sudo (補完)

(補完に必要な文字列を何も与えない)としたとき、今回の機能を有効にするかどうかは好みが分かれるところだと思いますが、一応安全な方を取って無効にし、普通にsudoで始まる履歴を検索して

sudo apt-get update

と補完するようにしました。

キーバインドは過去方向がC-P、逆がC-Nです。

# complete from history ignoring leading (sudo, '|', man, which, ..) in current prompt
# only complete in this way if there are some other input than those ignoring patterns
# examples with history:
#  ldconfig
#  make
#  make install
#  less
# case:
#  $ sudo <C-P>  => $ sudo ldconfig
#  $ sudo m<C-P>  => $ sudo make install => $ sudo make
#  $ wget -O - http://.../ | l<C-P> => $ wget -O - http://.../ | less
SMART_SEARCH_HISTORY_PATTERN='(sudo|\||man|which)'
function smart-search-history {
  local trim="$(echo "$LBUFFER" | sed -r "s/^.*${SMART_SEARCH_HISTORY_PATTERN} *//")"
  local old_leader="$(echo "$LBUFFER" | sed -r "/${SMART_SEARCH_HISTORY_PATTERN}/s/(^.*${SMART_SEARCH_HISTORY_PATTERN} *).+?$/\\1/p;d")"
  if [ -n "$trim" ]; then
    LBUFFER="$trim"
    zle $1
    LBUFFER="$old_leader""$LBUFFER"
  else
    zle $1
  fi
}
function smart-search-history-backward {
  smart-search-history history-beginning-search-backward
}
function smart-search-history-forward {
  smart-search-history history-beginning-search-forward
}

zle -N smart-search-history-backward
bindkey '^P' smart-search-history-backward
zle -N smart-search-history-forward
bindkey '^N' smart-search-history-forward

前回、空のプロンプトでEnterを入力するとlsするウィジェットを書いたときに$BUFFERの便利さに気づきましたが、今回もその流れで$LBUFFERというzleの変数を用いています。

現実逃避として格好のシェルスクリプト書き。今回はXのクリップボード操作コマンドであるxselを利用して、stdout (+stderr)をクリップボードにコピーする(更にまたstdoutに書き戻す)zshのグローバルエイリアスを書いてみました。

if exists xsel; then
  alias -g   B=" | xsel -bi" # stdout => clip
  alias -g  B2=" 2>&1 | xsel -bi" # stdout + stderr => clip
  alias -g  BB=" | (cat 1>&2 | xsel -bi) 2>&1" # stdout => clip and stdout
  alias -g BB2=" 2>&1 | (cat 1>&2 | xsel -bi) 2>&1" # stdout, stderr => clip and stdout
fi

zshにおけるグローバルエイリアスとは、alias -gで定義され、「コマンドライン中のどこでも」展開されるエイリアスです。普通のエイリアスは先頭でないと展開されませんが、グローバルエイリアスを用いることで、コマンド末尾につけるパイプ的な処理を効率化することが出来ます。

lessやgrepなどをLとかGとか設定すると便利です。

今回設定したB, B2, BB, BB2ですが、

  • B はstdoutをクリップボードにコピー
  • B2 はstdoutとstderrをクリップボードにコピー
  • BB はstdoutをクリップボードにコピーし、またstdoutに出力
  • BB2 はstdoutとstderrをクリップボードにコピーし、またstdoutに出力

となっています。
名前をC, C2, .. としなかったのは、

make CC=g++

などとしてコマンドライン中で普通に使われそうだったからです。この辺は完全に好みなので何でも良いと思いますが。

早速zshrcに追加したので、まだzshを使っていなくても、丸々コピペですぐに便利設定にできます。