Hatena::ブログ(Diary)

ヒルズで働くholidays-lの技ログ このページをアンテナに追加 RSSフィード

2011年08月23日

[開発]GNU makeのMakefileに、シェルスクリプトを自然に書くたった一つの方法

たった一つとか嘘です。

ググッても中々出てこなくて、ちょっといじってたらできちゃったので書き残しておきます。


GNU makeでは1行毎に1つのシェルで実行されるので、

foo::
	if true ; then echo "make love" ; fi

foo::
	$(SHELL) -c 'if true ; then echo "make love" ; fi'

と同じような挙動になります。


よってシェルスクリプトが複数行に渡る場合、

foo::
	if true
	then
          echo "make love"
	fi

なんて書いてしまうと、

foo::
	$(SHELL) -c 'if true'
	$(SHELL) -c 'then'
	$(SHELL) -c '  echo "make love"'
	$(SHELL) -c 'fi'

という感じで実行されることになるので当然エラーになります。


そこで以下のような書き方が良く用いられています。

foo::
	if true ;\
	then \
	  echo "make love" ;\
	fi

これ見た目上は複数行に分けて書けてはいますが、セミコロンの有無がワケワカランことになる上に、長くなってくると非常に猛烈に見辛くなります。しんどいです。



ここで、GNU makeでヒアドキュメントのようなことをする方法を紹介しておきます。

defineを使うと、通常の変数宣言とは違って改行を含めることができます。GNU make 日本語訳(Coop編) - 変数の利用法

define FOO
a
b
c
endef

ただこれをそのまま変数として

foo::
	echo "$(FOO)"

のように使ってしまうと

foo::
	echo "a
b
c
"

と展開され、これまた各行が1行ずつシェルに実行されてしまうのでエラーになります。


そこで、変数をexportして環境変数として扱います。

export FOO
foo::
	echo "$${FOO}"


ここまでくれば後は簡単でしょう。

echoしたものをshに食わせれば良いだけです。

define MAKELOVE
if true
then
  echo "make love"
fi
endef
export MAKELOVE
foo::
	echo "$${MAKELOVE}" | $(SHELL)
あら?インタラクティブシェルじゃなくなってしまって困るぞ…。
foo::
	echo "$${MAKELOVE}" > /tmp/$$$$ ; $(SHELL) /tmp/$$$$ ; rm -f /tmp/$$$$
とりあえずこれでお茶を濁し中…

どや?

ちなみに、シェル変数は相変わらず$$varnameと$を重ねて書かないといけないので、完璧に自然なシェルスクリプトになるわけではありません。あしからず。


みんなもっとmake loveしようぜ。

make: don't know how to make love. Stop.

2011年02月06日

[]FirefoxThunderbirdの起動の高速化を行なうスクリプト書いた

Fireboot - Firefox 起動高速化ツール

  • Thunderbirdの方をやってくれないし、
  • なんかちょっと表示がバグる感じなのと、
  • インスコが面倒なので、

同じようなことやるスクリプト書いた。

以下のスクリプト(geckoboot?)は、FirefoxとThunderbirdの拡張機能から不要な言語ファイルを削除することで、起動の高速化を図ります。

自分用に適当に書いているので、スクリプトを読めない人は、実行しないか又は読める人に挙動を聞いてください。

(ログ表示とかも自分が分かればいいや的に書いているので見にくいです)

あ、Cygwin上で

  • ~/.firefox -> /cygdrive/c/.../Mozilla/Firefox/Profiles/.../
  • ~/.thunderbird -> /cygdrive/c/.../Thunderbird/Profiles/.../

みたいなシンボリックリンクが張ってある環境で動作確認してます。

環境毎に適当に修正して使ってください。

#! /bin/sh
for d in $(find ~/.{firefox,thunderbird}/extensions/ -type d -a -name locale)
do
  cd $d
  echo * | /usr/bin/grep --quiet 'en' && rest=en
  echo * | /usr/bin/grep --quiet 'en-US' && rest=en-US
  echo * | /usr/bin/grep --quiet 'ja' && rest=ja
  echo * | /usr/bin/grep --quiet 'ja-JP' && rest=ja-JP
  if expr "${rest}" : '\(en\|en-US\|ja\|ja-JP\)' 1>/dev/null
  then
    delete=$(echo * | sed "s,${rest},,")
    if test -n "${delete}"
    then
      echo $(pwd)
      echo "rest is ${rest}"
      ls ${rest}
      echo "rm -r ${delete}"
      read -p 'delete above?[y/n]' yes
      if test "${yes}" = "y"
      then
        rm -r ${delete}
      fi
    fi
  fi
done

2010年09月19日

[]シェルスクリプトでsubstring

なるべく外部コマンドを使わずにやってる。(例えばbasenameの代わりに${foo##*/}など)

変数の先頭文字を取り出す方法

       ${parameter:offset}
       ${parameter:offset:length}
% /bin/bash -c 'foo=abcde ; echo ${foo:0:1}'
a
% /bin/zsh -c 'foo=abcde ; echo ${foo:0:1}'
zsh:1: unrecognized modifier `0'

素のshで使えるかどうかは知らない。

けど良く触れるシステムの/bin/shは大体/bin/bashなので、

自分ルール的に使っても良いことにする。

2010年09月10日

[]Thunderbirdの検索フォルダについて

検索フォルダ便利です。



別プロファイル(家と会社)でも同じ検索フォルダを使いたい時、virtualFolders.datだけをコピーしてもダメで、

検索フォルダを表すMail/Local Folders/foo(Mail/Local Folders/foo.msfと対になっているファイル)が必要です。

このfooは通常メール本文が入っているファイルなんですが、検索フォルダはメール本文が入っているわけではないので0バイトです。

foo.msfはインデックスファイルで、無ければ勝手に生成されます。


「新規フォルダを作ったとき、自動的に検索フォルダの対象にしたい」みたいな質問が上がってたりしますが、今のところ自動的には対象になりません。手でちまちま追加していくのも非常に面倒くさいです。


検索フォルダと検索対象・検索条件の関係は、virtualFolders.datに保存されているので、

私は適当な置換スクリプトを使ってscope=の行を更新しています。


(こういう仕組みなので簡単に拡張作れそうだけど、今のところ無いっぽいんだよね〜)

2010年03月24日

[]シェルスクリプトのtest

[[ EXPRESSION ]]

って書く理由は何なのでしょうか?

[ EXPRESSION ]

と何が違うのでしょうか?


ちなみに自分は敢えて

if test EXPRESSION

と書きます。


$ [ $foo = "" ]
-bash: [: =: unary operator expected
$ [[ $foo = "" ]]
$