それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bash-completion を自分で作る。独自補完を作ってみた。

bash-completion is 便利。

bash-completion って便利ですよね。zsh ユーザには興味のない話かもしれないけど、、zsh に比べ bash はどこでも使えるので便利なんですよね。

brew install bash-completion

また、各コマンドのcompletion もbrew や apt で一緒に入ってくれる。

最近だと、インストールすれば使えるようになっていてナニも考えなくてもイイようになってる。

自分で作ったコマンドはどうするか?

自分で作ったコマンドにも補完機能欲しいじゃん?となると自分で補完も定義することになる。zsh はこの辺たしか自動処理してくれたと思うんだけどね。

自分で作るのめんどくさい?→結構簡単

ぱぱっと読んだだけで、自分で補完機能が簡単に定義できることが分かった。

早速作ってみることに

とりあえず、独自コマンドの代わりに、bash で関数を定義し、関数の引数を補完するようにしてみる。

ステップ1:補完リストを定義して補完する

手順はこんな感じ

  • 関数作って(実験用)
  • 補完関数作って
  • 補完関数をロードして
  • 補完関数を試す。

関数と補完関数を作る

completion_test.sh
### 引数をecho するだけの簡単な関数。
function folder() {
  echo $@
}

### 補完関数。
_folders(){

  COMPREPLY=( takuya hatenablog hello completion )
}
### 補完関数と関数の関連付け
complete -F _folders folder

関数をロード

takuya@~/temp$ source completion_test.sh

使ってみる

takuya@~/temp$ folder

takuya@~/temp$ folder <TAB>
takuya hatenablog hello  world

おおおおお、補完された

ステップ2:補完リストを動的にしてみる。

このままだと、詰まらないし。いつでも固定の補完しか出来ない。

補完関数の中でコマンドをCallして補完の内容がその時の最新のフォルダ一覧になるようにしてみる。

補完関数の候補の改良

とりあえず、ls の結果を補完に表示してみよう。

### 補完関数。
_folders(){
  COMPREPLY=( $(  ls ~ ) )
}

このように書いて source コマンドで関数をリロードする。

実際に使ってみると。。。

実際にコマンド補完を実行してみる。すると$HOMEの内容がズラズラと出てくるようになる。

takuya@~/temp$ folder
Applications  Documents     Dropbox       Movies        Pictures      Sites         temp
Desktop       Downloads     Library       Music         Public        repos         work

これで、補完っぽくなってきた。

ステップ3:入力途中で絞込

ここ迄で補完候補が出るようになったけれど、まだ補完とは言い切れない。

それは入力途中の文字で絞込ができないから。

takuya@~/temp$ folder Do<TAB>
Applications  Documents     Dropbox       Movies        Pictures      Sites         temp
Desktop       Downloads     Library       Music         Public        repos         work

Do と打ち込んでも全てのリストが出力されてしまう。これは不便だ。これでは補完とは到底言い難い。

入力中の文字で絞込処理を書く

### 補完関数。
_folders(){
  COMPREPLY=( $(compgen -W "$(ls ~)" ${COMP_WORDS[COMP_CWORD]}  ) ) 
}

compgen -W で絞込した結果を候補に出るようにする。この時に入力途中の文字は 変数から取得する。

これで補完処理になる。

takuya@~/temp$ folder D<TAB>
Desktop    Documents  Downloads  Dropbox

これで補完処理になる。

出来たコマンドの置き場所

bash-completion は /etc/bash-completion.d/ に保存すれば、自動的にロードされるようになっている。

それは、bash-completion ば .bashrc で読み込まれるように記述されているため

bashrc

bashrc 中に次のような記述がある。

   if [ -f /etc/bash_completion ]; then
      . /etc/bash_completion
   fi

ちなみに homebrew 環境下の場合は次のようになっている。

  brew_prefix=`brew --prefix`
  # enable programmable completion features (you don't need to enable
  # this, if it's already enabled in /etc/bash.bashrc and /etc/profile
  # sources /etc/bash.bashrc).
  if [ -f ${brew_prefix}/etc/bash_completion ]; then
    source ${brew_prefix}/etc/bash_completion
  fi

さらに/etc/bash-completion/ には、次のように記述されており

# source user completion file
[[ $BASH_COMPLETION != ~/.bash_completion && -r ~/.bash_completion ]] \
    && . ~/.bash_completion
unset -f have
unset UNAME USERLAND have

ということで、自作のbash補完関数の保管場所は次の通り。

~/.bash_completion ## 個人用
/etc/bash-completion.d/ ## システム用

に置けば大丈夫。

もちろん、.bashrc に直接書いても問題ないんだけどね。

サブコマンド。

git add ファイル名
git commit -m "コミットログ"

のようにサブコマンドを取るものも、Completionでは定義可能。なのだが、自作コマンドの補完でソコまですることは殆ど無いので。サブコマンドについては参考資料にURLを貼っておくことにする。

自分でちょっと便利に使うためのコマンドでサブコマンドも作りこむことはまぁ少ないよな。

参考資料

bash-completionで独自の補完関数を作成する方法(gistyのサブコマンドを補完するやつ書いてみた) - 今日もスミマセン。

iOSのiCloud バックアップが作成されない時は、既存バックアップを消去する。

iOS のバックアップが取得されない。

iPhone や、ipad など iOS 機器のバックアップが取得されない、困った現象がある。

iPhone のバックアップは通常、2〜3日に一度自動的にiCloud に作られる。

自動的に作成されない時がある。

かれこれ1ヶ月ちかく、バックアップのスナップショットが作られないので、原因を調査した。

Apple ID だとか、iCloud の容量だとか。初期化とか色々試した。

iCloud 側のバックアップを削除してイチから作ります。

設定 一般 ストレージ iCloud ストレージ管理 バックアップ バックアップを削除

の順にたどって、該当のiOS機器のバックアップを選択し、バックアップを削除を選ぶ

IMG_1166

削除後に再度バックアップを入れるとうまくいく

削除後に、設定 iCloud バックアップ バックアップを作成 で、新規バックアップで作成するとうまくいく。

IMG_1165

バックアップ取れた

iOS / OSX のバックアップは時々オカシイ。

OSXのタイムマシンバックアップ(タイムカプセル)もそうなんだけど、時々バックアップ作成に失敗して「新規でバックアップを作りますか?」と謎なことを聞いてくる。

つまり、以前のバックアップと現在のバックアップとの継続性が上手く取れなくて、今までの履歴を全部捨てて、新しい「歴史」を始めるということなんだけど。。。

わかりにくいよね。

OSXの場合、タイムマシンバックアップが出来ないから「削除して新規」で作れとメッセージが出てくるのでまだわかる。

iOSの場合は、OSXみたいなバックアップ取得失敗のメッセージがないので、不便だ。

iOS の場合は、更にひどくてiCloud を手作業で削除する必要があるみたい。

本体のバージョンアップとか、リセットとか関係なく、iCloudとの整合性の問題なんだろうね。

バックアップはとりあえず、直近1週間の1世代が必須で、ソレ以前のものはアレばラッキー程度で考えてる。

OSX/iOSのバックアップはとにかく信用ならないので、直近1世代までしか「使いものにならないよね・・・」

OSX Serverで、自ドメイン内にMyOwn iCloud を作れればイイに・・・

関連資料

netatalkでLinuxサーバーをNAS TimeCapusleサーバーにする。 - それマグで!