理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

declare、typeset、そして local

declare とか typesetlocal まわりの使い方について。

まず、declaretypeset は、シノニムなので、この 2 つの差異は考えなくて良いと思います。このため、ここでは declare でひとまとめにして扱いたいと思います。 そういうわけで、declarelocal さえ区別できれば良いんですが、あんま変わらないんですよね。。。

属性の付与

declarelocal は、基本的に変数の宣言で使われますが、変数宣言とともに、その変数に対して属性を付与するときに使われます。

よく使われるのは、readonly のオプションですね。一度 -r 付きで宣言しておくと、その変数は readonly として扱われるようになり、それ以降で代入しようとするとエラーになります。

$ declare -r var="hoge"
$ var="fuga"
var: readonly variable

誤解されやすいのは、declare による属性の付与は、後出しが可能ってことでしょうか。 Google の出している Shell Style Guidereadonly を使った例が載っていますが、これ、declare を使っても同じようなことができます。

zip_version="$(dpkg --status zip | grep Version: | cut -d ' ' -f 2)"
if [[ -z "${zip_version}" ]]; then
  error_message
else
  readonly zip_version
fi
$ a="hoge"
$ typeset -r a
$ a="fuga"
a: readonly variable
$ echo $a
hoge

「整数型」っていう属性を与えることもできます。整数型という属性を与えることにより、浮動小数点が代入できなくなったりします。

$ x=3.14
bash: 3.14: syntax error: invalid arithmetic operator (error token is ".14")

また、expr(( )) とかを使わなくても、整数計算ができるようになったりします。

# declare -i を使った例
$ declare -i x
$ x=3+4
$ echo $x
7

# declare -i を使わなかった例
$ z=3+4
$ echo $z
3+4

ただ、この手の計算結果の格納は、分かりにくいので使わない気がします。 上記の例だと、x に文字列を代入しようとしたら計算結果が格納されているわけですが、前掲の通り、浮動小数点を代入しようとしたらエラーになるのは、あまり整合性が取れているとは思えないんですよね…。

この他、変数型が array であるとか、そういう属性を付けるときにも利用されたりします。

スコープ

というわけでスコープの話がでてくるんですが、local はわかりやすくて、その名前の通り「ローカル変数」を宣言できます。 Bash スクリプトのスタイルガイドは、結構 local 使えってところが多いですね。Google の Shell Style Guide もそうですし、以下の Defensive BASH Programming でも同様のことが言われています。

change_owner_of_file() {
    local filename=$1
    local user=$2
    local group=$3

    chown $user:$group $filename
}

Defensive BASH programming - Say what? より引用

スコープの話といえば、local の専売特許みたいなところがありますが、じつは typeset でもスコープの概念が導入されます。

foo (){
    declare FOO="bar"
}

bar (){
    foo
    echo $FOO
}

bar  # Prints nothing.

9.2. Typing variables: declare or typeset より引用

まぁ local の場合は、グローバル空間で宣言しようとするとエラーになるので、そのあたりは違いますね。

$ local p
bash: local: can only be used in a function
$ typeset p

参考文献

シェルスクリプトで部分文字列を切り出す

ときどき、シェルスクリプトで文字列の 3 文字目から 4 文字を切り出したいみたいなユースケースがあって、これまでずっと cut でやってた。

$ echo $str
1234567890

$ echo $str | cut -c3-6
3456

これ、じつは文字列操作でできる。

$ echo ${str:3:4}
4567

cut みたいな外部プロセスを呼び出すこともないので、シェルスクリプト性能おじさんも黙らせることができます。

はてな開発者ブログから参照されてたうれしい話

はてな開発者ブログから人知れずエントリが引用されてたのが、ちょっとうれしいことでした。

ちょっと Serf いけるかなーと思ってその仕組み調べてたときのエントリ。はてなブログだと、他のブログから言及されたときに通知くるんだけど、上記のエントリのどこから参照されてるのかまったくわからなくて、HTML ソース見てようやく把握した。

WAS Liberty Profileとは

WAS? 使ったことなかったんですけど、アプリケーションサーバですよね、みたいなかんじだったんですけど、さらに、 なに?WAS の Liberty Profile?なにそれ、全然知らんけどおいしいの?というくらいの状況でしたので、なんかよくわからなすぎました。

WAS Libery Profile

WAS の Libery Profile とは何なのかっていうと、WAS のプロファイルの 1 つです。WAS は、v8.5 から、2 つのプロファイルを提供するようになりました。

  • Full Profile
  • Libery Profile

Full Profile の方は JavaEE 仕様を全てサポートしたプロファイルで従来からのものです。

一方で、Liberty Profile は、IBM は「次世代アーキテクチャ」と呼んでますが、軽量・高速な起動をウリにしたプロファイルになっています。 その特徴はというと、必要な機能を選び、使用するフィーチャーのみを組み合わせて起動することができるとともに、構成を動的に変更できるということになります。

Docker にも Liberty Profile の Docker Image が提供されているように、 ランタイムの小型・軽量をウリにして、クラウド、コンテナ、IoT デバイスあたりを狙っているとのこと。

メチャクチャ分かりづらいんですが、Liberty プロファイルはランタイムであって Liberty サーバというサーバを立ち上げるものになっているようで、 Liberty サーバが、アプリケーション要求に従って (server.xml に書く)、必要なフィーチャーのロードとアンロードを行うようになっています。

実際に使ってみて

ローカル環境で起動させた場合、たしかに起動時間はかなり早いですし、server.xml でフィーチャーの構成を変えても、その反映は迅速です。 ローカルでの開発ではストレス感じずにいけているというのが今の実感です。

<server description="test server">
  <!--Enable features which you would like to use -->
  <featureManager>
    <feature>jsp-2.2</feature>
  </featureManager>
  <httpEndpoint id="appHttpEndpoint" host="localhost" httpPort="9080" httpsPort="9443" />
</server>
<!-- cited from https://dzone.com/articles/what-liberty-profile-ibm -->

また、コンビニエンス・フィーチャーという仕組みがあって、これは複数のフィーチャーをまとめたフィーチャーとして定義されています。javaee-7.0 とか、webProfile-7.0 とか。 これを使うとチマチマと個別のフィーチャーを指定することなく開発ができるので、開発初期の、フィーチャーへの要求すら安定していない頃は便利かもしれません。 Developer Works にも、

アプリケーション開発では、単純にコンビニエンス・フィーチャーを使用可能にして済ませておくことが多いようです。アプリケーションをデプロイする準備が整った時点で、アプリケーションが実際に使うフィーチャーの細かい指定でコンビニエンス・フィーチャーを置き換えて、メモリーとディスク・スペースを節約します。

https://www.ibm.com/developerworks/jp/websphere/library/was/liberty_fordev_intro/index.html

という記述があります。

とはいえ、開発中は動いたけど、変にフィーチャーを精査したら動かなくなったーとかザラにありそうなので、早い段階でフィーチャー構成を決めておきたいところではありますが。

参考文献

WAS Libery ProfileにおけるJVMオプションの設定方法

WAS Liberty Profile において、WAS のランタイムに JVM オプションを指定する方法を探し回っておりました。 この手の JVM オプションは、アプリケーションサーバを立ち上げるスクリプトさえ発見できればすぐなんですけど、今回は Eclipse 上で WebSphere Application Server Developer Tools(WDT) を使って立ち上げるようになっていて、JVM オプションの設定項目もなくてつらみがあった。

結論としては、サーバの基本構成を記述した server.xml と同じ階層にjvm.options ファイルを置いて、JVM オプションを記述すれば良い。 たしかにこういう仕組みだと、WDT に設定項目なくても納得する。

-verbose:gc
-Dconsole.encoding=UTF-8

参考文献

スタックトレースの出力が省略されてると思ったそのときに

よくあったんですよ、手元で例外が発生して原因を辿るためにスタックトレースを辿ってたら、おやおや、「… 3 more」とか出てて、原因が辿れねーぞっていうケース。

 HighLevelException: MidLevelException: LowLevelException
         at Junk.a(Junk.java:13)
         at Junk.main(Junk.java:4)
 Caused by: MidLevelException: LowLevelException
         at Junk.c(Junk.java:23)
         at Junk.b(Junk.java:17)
         at Junk.a(Junk.java:11)
         ... 1 more
 Caused by: LowLevelException
         at Junk.e(Junk.java:30)
         at Junk.d(Junk.java:27)
         at Junk.c(Junk.java:21)
         ... 3 more

… 3 more じゃねーんだオイ、おれはその more を見てぇんだよ、そうしないと原因が分かねーだろが。

もうね、ぼくが悪かった。無知は罪ですごめんなさい。スタックトレースを全出力する JVM のオプションがあるんじゃない???とかしたり顔で言ったりして本当にすみませんでした。反省しております。

文字"…“を含む行が存在することに注目してください。これらの行は、この例外のスタック・トレースの残りが、この例外により引き起こされた例外のスタック・トレースの下からのフレーム数と一致することを示します。通常の(「原因となる例外」をキャッチするのと同じメソッドからラップされた例外がスローされる)場合、この短縮形を使用することで、出力の長さを大幅に短縮できます。上の例は、次のプログラムを実行することで生成されます。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Throwable.html#printStackTrace–

ちゃーんと Javadoc に書いてあったんですね。省略は省略でも、「出力が重複してるから省略」してたってこと。Java は偉いよ。ホントえらい。 Java に対して無知すぎる。なんとかしていきたい。

ありがとうLDR

Live Dwango Reader が、2017/8/31 に、ついにサービス終了するそうです。

いつか来るとは思っていましたが、ついにこの日が来たのだと、そういう感覚でした。すごく残念です。本当に残念です。

大学生の頃からの情報収集手段だった

ぼくの情報収集手段の最たるものは、いつも LDR でした。これは、大学のときからずっとだと思います。 OPML から雑に数えると、LDR に登録していたフィードの数は 1,400 くらいでした。

$ grep -i '<outline ' export.xml | grep xmlUrl | wc -l
1391

ぼくにとって、このフィードを一番効率的に捌けたのは常に LDR でした。 vi と同じようなキーバインドで流れるようにフィードを消化していけたし、「Pin を立てる」という概念で、気になったフィードの抽出と、そのフィードの消化(読みこみ)のフェーズを分ける運用も簡単でした。

API が公開 (仕様が公開されていたというよりは、LDR で使用されている JavaScript を読み解くことで、API をどう使えば良いかが分かった) ので、容易にツールを作ることもできました。

最初はブラウザベースで使用していましたが、スマートフォンアプリも発達し、他アプリとの連携も簡単にできるようになりました。 今は、ブラウザベースからスマートフォンのアプリ経由になりましたが、それでも LDR を使用し続けています。

Taskchute の記録を見る限り、今でも 1 日 24 分ほど、LDR に費していました。 タイトルレベルであれば、今でも軽く千を超えるエントリを 1 日で目を通しています。これも LDR という優れた RSS リーダがあったからだと思います。 他の RSS リーダを使っていたとすると、もしかすると情報収集の手段として RSS を選択していなかったかもしれません。

LDR の操作性は、それほどまでに一線を画していたように思います。

RSS の未来

2013 年に Google Reader がサービス停止し、そして今回の LDR のサービス停止と、RSS という技術にとっては冬の時代を迎えているのかもしれません(もちろん、Podcast なんかはまだまだ続くと思いますが)。

それでも、ぼくは Pull 型の情報収集手段、自分の興味ある分野を aggregate してくれる技術としては、これからも RSS にしがみつきます。 今のところはまだ、RSS が最良の手段だと思っていますし、依存し続けると思います。

本気で LDR から移行を考えなければならないのは悲しいですが、Feedly、Aol Reader など、使用性を試していきたいと思います。 あそこまで優れたサービスを無償で提供しつづけてくれた Livedoor、そのサービスを引き受けてくれた Dwango、10 年以上、本当にありがとうございました。

シェルスクリプトにおける [ と [[

シェルスクリプトで条件分岐を書くとき、[ を使ったり [[ を使ったりすることになると思います。

POSIX の test にも記載がありあすが、[test と同じ機能を持つことになっており、同じ実装であることも多いです (ただし、[ として実行されるか、test として実行されるかに依って挙動が変わり得る)。

一方で、[[ は POSIX で定義はされていない、Bash 等の高機能シェルでの拡張になります。

[[[ は、当然ながら同じような機能を持っています。そりゃ、後者は前者の拡張ですからね。一方で、「拡張」であるが故に、[[[ で異なる挙動も存在します。

演算子

たとえば比較の演算としては以下のような挙動のちがいがあったりします。なお、[ への有無については、POSIX 定義という観点であって、シェル実装によっては普通に使えるものもあります。

機能 [ [[ 備考
文字列の大小比較 a \> b a > b [ の場合、リダイレクトと誤解されないようにエスケープが必要です
AND 条件 s1 -a s2 s1 && s2 実際のところ、-a は POSIX で 時代遅れであり、POSIX 標準に準拠する場合は使わないようが良いよ とされてます
OR 条件 s1 -o s2 s1 || s2 同上
パターンマッチ なし $a = a*
正規表現マッチ なし $a =~ ^hoge
ファイルの新旧チェック なし $file1 -nt $file2

このあたりの差異の背景には、POSIX にも記載があります。

Some additional primaries newly invented or from the KornShell appeared in an early proposal as part of the conditional command ([[]]): s1 > s2, s1 < s2, str = pattern, str != pattern, f1 -nt f2, f1 -ot f2, and f1 -ef f2. They were not carried forward into the test utility when the conditional command was removed from the shell because they have not been included in the test utility built into historical implementations of the sh utility.

test

その他の挙動

  • [[ では変数をクオテーションで囲まなくて良い
$ var=''
$ [ $var = '' ] # [ = '' ] と展開されてしまうので NG。クオテーションが必要。
sh: [: =: unary operator expected
$ [[ $var = '' ]
$ file="file name"
$ [ -f $file ]    # スペースを含んでいるので、クオテーションで囲まないと失敗する
sh: [: file: binary operator expected
$ [[ -f $file ]]  # 成功する
  • [[ の場合、( 等をエスケープする必要がありません。
$ [ -f "$file1" -a \( -d "$dir1" -o -d "$dir2" \) ] # グルーピング用の括弧もエスケープの必要有
$ [[ -f $file1 && ( -d $dir1 || -d $dir2 ) ]]

※先述の通り、-a-o は POSIX としては、obsolete とされています。

  • [[ の場合、文字列の大小比較でエスケープする必要がない
$ [ a < b ] # シェルにリダイレクトと解釈される
sh: b: No such file or directory
$ [[ a < b ]]


$ [ a > b ] # こちらはエラーすら出ないで、「正常に」ファイルが作成されてしまう。
$ ls b
b

ポータビリティ

状況にも依りますが、ぼく自身はそこまでポータビリティを重視してシェルスクリプトを書かないといけないとは思っていません。 環境がかわったら、シェルスクリプトから呼びだされるコマンドの挙動もちがうでしょうし、そのまま別環境へ移植というのはまぁ無いだろうと思っています。 それに、ポータビリティを重視するにしても、シェルの個別拡張を使用せずに POSIX だけで書こうというのはすごく難しいですし。。。

そういう考え方なので、[[ の方を使うかな。

参考文献

Fire TV Stick のある生活

このあいだ開催されていた Amazon の PrimeDay で Amazon Fire TV Stick を購入しました。

Fire TV Stick (New モデル)

Fire TV Stick (New モデル)

もともとこの手の機器として、Chromecast を持っていました。 Chromecast 自体に不満はなかったのですが、部屋の TV に接続するようになったので、リビングの TV 用のものが欲しくなり、ちょうど PrimeDay でかなり安くなっていたので購入した次第です。

ところがこれ、マジで購入して良かった。ライフチェンジングなかんじでした。 基本的に非常に満足していて、この買って良かった感は、録画機器の無い時代に購入した torne 以来です。

ChromeCast との違い

Chromecast というのは基本的に、スタンドアローンで動作しません。 Chromecast というその名称が冠するとおり、モバイル端末その他の端末から、映像や音声を Cast (投影) することでテレビにその内容を映し出します。

一方で、Kindle Fire TV は単独で動きます。 モバイル端末の助けなしに、HDMI 端子に差し込むだけで、アプリケーションのダウンロード、PrimeVideo や AbemaTV のテレビへの投影を行ってくれます。

「モバイルの小さい画面での操作から解放されたこと」、これが Kindle Fire TV で大きく改善されたことになります。

音声検索の精度が思いの他良い

Fire TV Stick は、スタンドアローンで動作するが故にリモコンが同梱されていて、そのリモコンには音声検索機能が搭載されています。 さすがは Alexa の Amazon と言うべきか、この音声検索がすこぶる正確です。

リモコンでキーボードを操作するのはさすがに至難なのですが、音声検索が優秀すぎるが故に、そういったストレスを感じることがありません。テクノロジー、確実に進化している…。われわれにキーボードなんてインタフェースはいらんかったんや!! (なお、無線 LAN のパスワード入力ではキーボード不可避)

f:id:kiririmode:20170722163030j:plain

チャネル

あんまり考えなしに衝動で買ってしまったので、Hulu とか Netflix、 Amazon Prime Video くらいしか見れないんだろうなと思っていたんですが、良い意味で裏切られました。 ネイティブなアプリがダウンロード可能で、それをインストールすることで動画に限らずチャネルを増やすことができます。

残念ながら日本のチャネルは多くないんですが、Netflix、hulu あたりはもちろんありますし、DAZN もあります。 ぼくにとって嬉しかったのは、

とかがあることですね。 とくにdアニメストアは、なぜか絶対無いよなと思い込んでいたので、良い意味で裏切られました。

要望

あとは、PC からの直投影もサポートしてくれると嬉しいんですよね…(Chromecast はこれができる)

CDIにおけるProducerメソッド

JavaEE 良くわかっていないのですが、それでもプロジェクトが JavaEE 標準だーウオーという状況っぽいので、ちょっと勉強をしはじめております。 ぼくが Java に対して得意意識を持てないのは、こういうところの知識がないのもあるので、そのへんを払拭していこうとがんばらなければ。

今日ははじめて、@Produces というアノテーションを知りました。

@Produces

DI というと、今までずっと「コンテナがオブジェクトを注入する際、どのクラスのオブジェクトを注入するのかはコンテナが決定する」と思ってたんですよね。 開発者は、コンテナに対して型情報といわゆる限定子(非推奨みたいだけど @Named とか、@Qualifier を使って作成したものとか)を教えることで、何を注入してほしいのかを伝えるものだと。

じつはそのあたりには別解があって、コンテナではなく、開発者自身がオブジェクトを生成し、それを注入するようにできる方法があります。 それが Producer メソッドと呼ばれるメソッドをつくる方法で、Producer メソッドの作り方というのが、@Produces アノテーションをメソッドに付与することだと。

Producer メソッドを作ると、DI コンテナが注入対象のフィールドだったり引数だったりを見つけると、その注入対象の型を返却してくれる Producer メソッドを呼んでくれるようになります。

このため、Producer メソッドで注入すべきオブジェクトを生成して、それを返却してやるだけで、動的に注入するオブジェクトのクラスを切り替えたりもできるようになると。なるほど便利だ。

このように、Producer メソッドでは、実行時に注入する型を変える他にも

  • Bean ではないようなオブジェクトを注入する
  • 注入するオブジェクトに対して、コンストラクタでの初期化以外のカスタマイズを実行する

といった特徴を持たせることができます。 百聞は一見にしかずなのですが、Weld 2.4.3.Final - CDI Reference Implementation に Producer メソッドで、プリミティブとしての int を生成し注入するための Producer メソッドの実装例がありました。

import javax.enterprise.inject.Produces;


@ApplicationScoped
public class RandomNumberGenerator {


   private java.util.Random random = new java.util.Random(System.currentTimeMillis());

   @Produces @Named @Random int getRandomNumber() {
      return random.nextInt(100);
   }
}

こちらは、Strategy パターンの型を、動的に切り替える例

import javax.enterprise.inject.Produces;

@SessionScoped
public class Preferences implements Serializable {

   private PaymentStrategyType paymentStrategy;

   ...

   @Produces @Preferred
   public PaymentStrategy getPaymentStrategy() {

       switch (paymentStrategy) {
           case CREDIT_CARD: return new CreditCardPaymentStrategy();
           case CHECK: return new CheckPaymentStrategy();
           case PAYPAL: return new PayPalPaymentStrategy();
           default: return null;
       }
   }
}

たいへんに、なるほど〜〜〜感あります。

ただ、これを多用すると、DI における依存性解決がコードから読み取りにくくなるので、まぁ用法用量を守ってお使いくださいという感じなんでしょう。