Home

うしねずみの技術メモ

カップ焼きそばのアレンジレシピ

おなかすいた。

最近、青唐辛子のしょうゆ漬けを作ったのだけど
なぜか全然辛くなくて(前回は猛烈に辛かった)
スパイシーなもの食べたい欲求が。

まー、疲れて帰ってくると特に。

材料

  • 一平ちゃん(焼きそばならなんでも)
  • 鷹の爪
  • ホール花椒(ホールじゃなくても)
  • 黒コショウ
  • オイスターソース

作り方

  1. 鷹の爪と花椒を刻む
  2. 普通に一平ちゃんを作る
  3. オイスターソースと「1」を入れて混ぜる
  4. 黒コショウをたっぷりかける

うまい。。。

スパイスをすりつぶすために乳鉢が欲しくなりました。

余談。
Mocosキッチンで、もこみちさんが「じゃあまずは最初に乳鉢を準備してください」
って言ってて、そんなの無いのでスタート地点にすら立てませんでした。

bashのリダイレクトとパイプとファイルディスクリプタ

  • 2016-11-02 (水)
  • bash

最近通勤中にMan page of BASHを読むのが楽しい。
https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html
数年前なら読んでもちんぷんかんぷんだったろうが
今読むとBASHの知らない仕様やその使いどころがわかって楽しい。

BASHの中でもよく使うのに奥が深い(というか直感的なのに難しい)のが
リダイレクト、パイプと、それに関わりの深いファイルディスクリプタである。

いじくりながら理解を深めたいと思う。

環境依存のことも言ってしまうかもしれないので
とりあえずバージョン書いておきます。
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)

まず、標準出力と標準エラー出力にそれぞれ
“stdout”と”stderr”を出力するスクリプトを書く。

実行してみる。

標準出力をファイルに書き出してみる。

ファイルディスクリプタの1(以降fd1)をout.txtに出力しているので
端末にはstderrだけが出て、stdoutはファイルに出力されている。

次に標準エラー出力をファイルに出してみる。

ファイルディスクリプタの2(以降fd2)をout.txtに出力しているので
端末への出力とファイルの内容は先ほどと逆になる。

次に、標準出力も標準エラーも両方ファイルに出力する。

リダイレクトは左から順に解釈される。
ファイルディスクリプタの出力先を「->」で表すとこうなる。

[初期状態]
fd1 -> 端末
fd2 -> 端末

[1> out.txt](fd1の出力先をout.txtにする)
fd1 -> out.txt
fd2 -> 端末

[2>&1](fd2にfd1を複製する)
fd1 -> out.txt
fd2 -> out.txt
となる。

ここまでは基本的なことしかやってないのだが
既に1つの疑問が出てくる。
さっきの書き方で、test1.shの2行目の処理を書いてみると
[初期状態]
fd1 -> 端末
fd2 -> 端末

[1>&2](fd1にfd2を複製する)
fd1 -> 端末
fd2 -> 端末

、、、最初と変わってない。。。
つまり何も起きなかったことになる。

落ち着いてもう少し考えてみる。
リダイレクトは左から処理されるとman bashに書いてあるが、
スクリプトの中と外のリダイレクトとはどちらが先に処理されるのか?

こんな実験をしてみる。

fd1とfd2は両方とも端末を指している。
次にこんなシェルスクリプトを書く。

これをリダイレクトとともに実行する。

シェルスクリプト内部ではすでにfd1とfd2の指す先が変わっている。

さっきのtest1.shのfd複製で何も起きない疑問を
もう一度考えてみるとこうなる。
$ ./test1.sh 2> out.txt
を実行した場合

[test1.sh開始時]
fd1 -> 端末
fd2 -> out.txt

[1>&2](fd1にfd2を複製)
fd1 -> out.txt
fd2 -> out.txt
これで無事に”stderr”はout.txtに出力される。

つまり、リダイレクトはコマンドの実行前に処理されて、
コマンドを実行しているコンテキストの
fdが指す先の初期状態になる、ということ。

次はパイプの処理を見ていく。
man bashのパイプの説明は次のとおりである。

command | command2
command の標準出力は command2 の標準入力にパイプで接続されます。
この接続は、コマンドで指定したどのリダイレクションよりも先に実行されます。

ここで標準出力と標準エラーを両方パイプに渡すよくある例。
標準入力を標準出力とファイル両方に出すteeコマンドを使って
両方パイプに渡せていることを確認。

これを先ほどの書き方で説明すると
[初期状態]
fd1 -> 端末
fd2 -> 端末

[パイプ接続]
fd1 -> fd0 @ cat
fd2 -> 端末

[2>&1]
fd1 -> fd0 @ cat
fd2 -> fd0 @ cat

fd1とfd2をlsするtest2.shを実行するとこうなる。

もう少しパイプの話。
man bashには次のように書いてある。
|& を使うと、command の標準エラー出力もパイプを通して
command2 の標準入力に接続されます。 これは 2>&1 | の短縮形です。

|& は標準出力も標準エラーもパイプにつなげてくれるんだ、、
と理解すると誤った使い方をしてしまう。

一見、標準出力だけファイルに出力して
標準エラーはcatに渡せるように見えるが、
両方ともファイルに出力される。

man bashの説明のとおり展開してみれば一目瞭然。

慣れている人なら見たらすぐわかると思うが順序を追っていくと、
まずパイプが一番最初に処理され、
残りのリダイレクトが左から処理されるので
[初期状態]
fd1 -> 端末
fd2 -> 端末

[パイプ接続]
fd1 -> fd0 @ cat
fd2 -> 端末

[1> stdout.txt]
fd1 -> stdout.txt
fd2 -> 端末

[2>&1]
fd1 -> stdout.txt
fd2 -> stdout.txt

当然、catには何も渡らない。

標準出力はファイル、標準エラーはパイプに渡したいならこうなる。

標準出力と標準エラー出力を入れかえる、という例が説明されていることもある。
こんな感じ。

これについても、fd1もfd2も端末を指しているのだから、
入れ替えても同じでは??
って思っていたが、パイプが先に接続されることが分かっていれば
先ほどの「->」記法で説明できる。

でもこの例の場合、最終的に下記の状態を作りたいのだから
fd1 -> 端末
fd2 -> パイプ
下記の方法が一番手っ取り早いのでは。
※ttyについてあまりちゃんと理解していないが。。

色々書いてみたが、実際に使うときはこんな色々考えず、
直感的な動作をするリダイレクトって、すごいなぁ。。

shell scriptでlong optionを処理する

仕事でシェルスクリプトを時々書く。

オプション処理にはgetoptsを使っている。
オプションの種類が増えてくると
意味が分かりやすいロングオプションが使いたいくなるが
getoptsではショートオプションしか使えないらしい。

こちらの記事や
bash によるオプション解析
こちらの記事が
bashでロングオプションとショートオプションの両方に対応する
とても参考になり、やり方を考えてみた。

環境依存なgetoptはなるべく使いたくないし
自作せずに既存の方法をなるべく使って実現したくなる。

こんな感じかなぁ。。
ポイントはロングオプションが指定されたらoptとOPTARGを書き換えて
それ以降の処理をショート/ロングオプション共通にすること。

必須のオプション引数が指定されなかった時に
エラーを表示する方法がないので自前で「check_arg_exit」を定義しておき
必要なcase節に書いておく。

全部自前の「check_arg_exit」に統一しようと思って
getoptsのオプション指定の先頭にコロンを足して
エラー表示をしないようにしたのだけど

これだとfオプションが引数無しで使われたときにcase文が?節に落ちる。
未定義のショートオプションを使った場合も?節に落ちるので
エラー表示を「オプション引数がない」にすればよいのか
「未定義のオプション」にすればいいのかわからないので諦めて
ショートオプションのエラー表示は全部getoptsに任せることにする。

(2016/10/16訂正)
man bashを読むとgetoptsは「silent」(オプション指定の先頭がコロン)なら
必須引数無は「:」、未定義オプションは「?」がoptにセットされるので区別可能。
「not silent」ならいずれも「?」がoptにセットされるらしい。
でもこのときoptが「:」や「?」になっていて
元のオプション文字はOPTARGに入っているので
自前のエラー処理と共通化できない。
ので、結局ショートオプションのエラー表示はgetoptsにお任せ。

未定義のロングオプションが指定されたら
エラー表示したいのでcase文の最後のアスタリスク節は必要。
その前の?節が無いと、未定義のショートオプションを指定した時に
getoptsからエラー表示が出てアスタリスク節でも自前のエラー表示も出てしまうので必要。

これでやりたいことは全部できてそう。
・ロングオプションを処理できる
・ロングオプションに引数指定できる
・未定義オプションでエラーを表示
・必須のオプション引数が無いときにエラー表示

あと出来てないのはこれぐらいだろうか。
私の用途ではこれらの要件は不要なので、もう満足です。
・通常引数の後にオプション指定
・引数があってもなくてもよいロングオプション

主な実行結果。

cutコマンドでデリミタ(区切り文字)の連続を1つの区切りにできない

cutコマンドでは、デリミタの連続を1つの区切りとして扱えない。

できるオプションがあるのだろうと思って調べてみたが、
どうもそういう機能はなさそうで
sedで区切り文字を1つにまとめてからcutするか、
cutじゃなくてawkを使うのが一般的の様子。

一番使うコマンドを調べるというよくある例。

確かにこれでやりたいことできるし、
awkは覚えておくといろいろ役に立つのだけど、
cutのようにただ列を抽出したいだけの用途の場合、
awk ‘print {$2}’
をタイプすることすらメンドクサイ。

mcut.shというシェルスクリプトを書いておきます。
(名前のセンスはないけど、my cut コマンド)

これで先ほどの例はこれで書ける。

メールの引用の中に埋もれたURLを開く

メールの中から目的のURLを見つけたのだけど
改行がたくさん入っていて下記のようになっていることがあります。

元のURL
http://hogehoge/fugafuga/piyopiyo/mosimosi.html
何度も引用されて、、
> > http://hogehoge/fu
> ga
> > fuga/piyopiyo/mosi
> mo
> > si.html

こんなURLを一発で開きたい。
というperlスクリプトを作りました。

使い方は

  1. Ctrl-cで文字列をコピー
  2. スクリプトをダブルクリック→explorerで開く

ただし、引用するごとに「> 」(半角大なり、半角スペース)がつくことを前提にしていますが。

パーセントエンコーディングをデコードするperlスクリプト

  • 2016-01-24 (日)
  • perl

仕事していて日本語が含まれたURLを扱うことがあるのですが
そのまま資料やメールに張り付けると長くて見栄えが悪く
困ってました。

クリップボードにコピーしたパーセントエンコーディングを含む文字列を
日本語にデコードして再度クリップボードに戻すPerlスクリプトを作りました。

使い方は

  1. パーセントエンコーディングを含むURLをCtrl+cでコピー
  2. スクリプトをダブルクリック
  3. Ctrl+vで貼り付け

ノートパソコンのWifiの回線速度が遅い(スマホが無線LAN子機に)なる

最近自宅のノートパソコンを新調しました。
が、問題発生。

Wifiの回線速度が出ない。。。
おまけにブラウジングしていると「読み込めませんでした」というエラーで
たびたび再読み込みが必要になる。

これは困った。。。ということで対策を検討してみました。

うちは下図のような構造になっています。

自宅のWifiの位置関係

2階の赤丸のところに有線LANとDesktop PC、無線LAN親機
1階の青丸のところにWifi接続のノートパソコンです。

2階の有線LANでは実測100 Mbpsぐらい出ているので
自宅のインターネット環境自体は問題なし。

ちなみにノートパソコンのWifi回線速度を測ってみると4Mbpsほど。
まったく同じ場所で、スマホをWifi接続して測ってみると8Mbpsほどは出ている。
おまけにスマホで再読み込みが必要になることはほとんどない。

うーん、これは受け側(ノートパソコン)の感度の問題に違いない。

ということで近くの家電量販店に行って相談。
事情を説明し、「受け側の感度の問題だと思うんですけどねぇ」と話してみる。

家電量販店の店員さん曰く、
「受け側の問題だったら無線LAN子機で改善すると思いますが
親機の無線強度が弱いことが原因の可能性もありますし、、、」
とのこと。

無線中継器というのがあるのをはじめて知ったが、
うちの家の構造は図の通りなので、階段に中継器を置くと
距離的には親機とノートパソコンの直線距離より遠くなる。
効果のほどはわからないとのこと。

と、ここまで相談したところで、いったん帰って考え直すことに。

自宅に帰ってスマホに回線速度で負けている
ノートパソコンと向かい合っていると、あるひらめきが。

スマホは速度出ているんだから、スマホ経由でテザリングすればいいジャーン。

そしてスマホのメニューを見ていくと
「USBテザリング」なるものがあることに気づく。

さっそくノートPCとUSBケーブルで接続し、
USBテザリングON!!

しばらくしてノートパソコンのタスクトレイのネットワーク状態を表すマークが
無線の電波マークから有線接続のマークに。

おぉぉ。。

そしてワクワクしながら、再度回線速度の測定してみる。

。。

。。。

。。。。。。

15.8 Mbpsです。

おぉおおおおおおおおお!!

 

なぜスマホ単体のWifi接続より回線速度が出ているか謎ですが
とりあえず、結局何も買わず、問題解決となりました。

テザリングというと、出先などのネットワーク環境がない状態で
PCの通信をモバイルネットワークに乗せるもの、というイメージでしたが、
自宅の無線LANの子機としても使えるんですね。(当たり前ですが)

スマホでのテザリングがパケット定額になるかどうかは
お使いの各キャリアさんに確認してくださいね。

eclipseでphpコードをデバッグするとApacheが落ちる

どうも、うしねずみです。
最近eclipseを使ったPHPの開発でハマった(ハマっている)ので書きます。

いまPHPの開発にeclipseのパッケージの一つである、Eclipse for PHP Developersを使っているのですが、どうもコレ、Vistaとの相性が悪いらしい。というより、PHPのデバッガとVistaの相性が悪いらしい。

この開発環境は
Window>Preference>PHP>Debug
のPHP Debuggerの項目でXDebugとZend Debuggerを選べるのですが、ネットで調べてみるとVistaPCでXDebugを使ってデバッグするとApacheが落ちるらしい。私はZendを使っていたので関係ないかと思いきや、Apacheが落ちる落ちる。

最初は2,3回に1回だったので落ちたら再起動して我慢していたのですが、そのうち落ちる頻度が増え、PHPのソース内で読み込んでいるswfファイル(Flexアプリケーション)の挙動まで安定しなくなってきました。もう少し具体的に言うと、Flexアプリ側からPHPにアクセスしてDBからデータを拾ってほしいのですが、PHPから正常に値が返ってこない。最初はFlexアプリ側でどんなに探してもバグらしきものが見つからなくて困りました。しかしブラウザからアクセスすると正常な挙動を示すので、どうやらPHPのデバッガのせい。しまいには、eclipseまで落ちまくるようになって、ホントに困りました。

今のところブラウザからアクセスした感じではアプリ全体にバグがなさそうなのでいいですけど、このままだとPHP部分とFlex部分の結合テストができないなー。。。
あー、面倒だ。

SVNでマージしようとしたらRetrieval of mergeinfo unsupported

どうも、うしねずみです。

最近Flexアプリをeclipse + FlexBuilderプラグイン + subclipseで開発しています。subclipseって言うのはeclipse上で使えるSVNクライアントのプラグインです(他にはsubversiveというのが有名らしい)。

それで、今日コードをSVNリポジトリのtrunkにマージしようとしたら問題が。。。

Retrieval of mergeinfo unsupported by “svn+ssh://hogehoge”

って言われるのです。
どうやら、SVNサーバのバージョンが古くて、SVNクライアント側が必要としている情報が見つからないらしい。ちなみに subclipseのバージョンは1.6.5で、SVNサーバのバージョンは1.2.3。SVNのバージョンは”svn –version”で確認できます。

さて問題が起きた流れを説明してみます。

まず、マージしたいプロジェクトを右クリックして「Team」>「マージ」を選択します。するとマージのダイアログが立ち上がります。
ここです!
私は機能ブランチが完成してトランクにマージしようとしていたので「Reintegrate a branch」 を選びました。これが失敗の原因。 私が使ってるバージョンのsubclipseでは、ブランチを再統合しようとすると、マージすべきリビジョンの範囲をブランチの過去のマージの情報から勝手に取得してくれるっぽいのですが、SVNサーバのバージョンが古いと「ブランチの過去のマージの情報」っていうのが残らないらしく、「そんな情報はないよ」みたいに怒れられるっぽいです。

なので「Merge a range of revisions」を選んで、手動でマージするリビジョン範囲を指定しましょう。
なお、この場合の注意点は、今回どのリビジョンまでをマージしたかを記録しておかないと、次のマージの時にマージすべきリビジョン範囲が分からなくなります。
例えば今回リビジョン1000までマージしたのなら、次回のマージは1001~HEADリビジョンとなるはずです。

SVNはマージの方法とか理解しにくくていつも苦労します。それから「リビジョン」に対する考え方がSVNのコマンドラインクライアントとtortoiseSVN(メジャーなSVNクライアントソフト)では違うらしく、注意が必要です。

TortoiseSVN とコマンドラインクライアントを比較すると、リビジョン範囲を指定する方法に重要な違いがあります。これを思い浮かべる簡単な方法は、フェンスの柱と、フェンスの板について考えることです。コマンドラインクライアントでは、 で指定した 2 本の 「フェンスの柱」 のリビジョンを使用して、マージする変更を指定します。TortoiseSVN では、「フェンスの板」 を使用して、マージする変更セットを指定します。マージするためのリビジョンを指定するログダイアログを使用する場合、チェンジセットとしてどこに各リビジョンが現れるか、明白になるためです。かたまりとしてリビジョンをマージしていると、subversion book にある方法では、今回 100-200 をマージし、次回に 200-300 をマージすることになります。TortoiseSVN では、今回 100-200 をマージし、次回に 201-300 をマージします。この違いは、メーリングリストでたくさんの論争を巻き起こしてきました。私たちは、コマンドラインクライアントと違うことを認めます。しかし、大多数の GUI ユーザにとって、私たちが実装した方法の方が理解しやすいと信じています。

でも、SVNが無い開発はデグレしまくるだろうし、恐ろしくてやってられません。以前マージを手動で(WinMergeというマージツールを使って)一つずつファイルを開いてやったことがありましたが、死にました。
これからもお世話になります、SVN。

Flexで画像のロードが終わるまで待機したい(Sleepが無い!!)

どうも、うしねずみです。
Flexでの画像のロードについて、悩んだので書いてみます。どうやらFlexにはSleep関数が無いようで、そのせいで色々悩みました。まずは、画像をロードする方法をまとめてみます。

方法その1: LoaderをそのままaddChildする

例えばロードした表示するだけの時は以下のように書きます。

loaderをuicにaddChildしたものをaddChildすれば画像が表示されるというちょっと不可思議な感じ。

方法その2: COMPLETEイベントのリスナーを登録しておく

方法その1だと、画像を表示するだけなら出来ましたが、画像を扱ってどうにかしたいときは困ります。そういう時は以下の方法。

4行目でloadComplete関数をロード完了時のイベントリスナに登録しています。よって、画像の読み込みが終わるとloadComplete関数に制御が飛んで、その中で画像を使った処理ができます。test関数はロードが完了する前にリターンされます。よってtest関数を呼んだ側の処理が画像のロードの間待たされるわけではありません。

さて、ここで問題が

実はこの「ロードが終わる前に制御が戻る」という性質が厄介だったりするのです。最近画像のラッパーを作っていたのですが、その時に「画像のロードが終了するまで呼び出し側の実行を待機したい」ということがありました。例えば以下のようなラッパーを作ったとします。

このクラスは、画像のアドレスを渡してnewすると、コンストラクタ内で画像をロードしておいてくれるクラスです。これだけだとアドレスと画像を持っているだけですが、他にもこの画像に関する様々な情報をまとめて持たせるためのクラスです。
さて、このクラスは例えば以下のように使われます。

ここで問題が生じるのです。MyImageWrapperのコンストラクタはロード処理を開始するだけで、ロードが終わるまで待ちません。なのでまだMyImageWrapperのloadCompleteが呼ばれないうちに制御が返ってきます。すると2行目でまだmyImage.imageDataはnullなので、「nullはaddChildできません」というエラーになるのです。
じゃー答えは簡単。imageDataがnullじゃなくなるまで待てばいいんだな、と思って次のように書き変えました。

ところが、このソースを実行してみると、永久にloadCompleteが呼ばれず、5行目にたどりつくことができません。Flex(Flash)の中で「CPUが空き状態になるまでloadCompleteの実行は待機する」という仕様になっているのでしょうか。

じゃあ空ループじゃなくてSleepすればいいんだな。と思って調べたのですが、どうやらFlexにはSleepが無い模様。
さて、困った。

Timerを使って実装することもできなくはないです。以下のようになります。

タイマは、一定時間ごとに登録したリスナを呼んでくれます。ここでは無名関数をその場で定義して登録しています。つまりこのタイマは100msごとに画像のロードが終わってるかどうかをチェックして、もし終わってたらaddChildを済ませて、自分自身(タイマ)を止めてくれます。
しかしこれはこれでなんか面倒だしすっきりしません。また、timer.start()のところで実行が待機するわけではないので別のところで画像データを使いたくなったときに既に画像のロードが終わっている保証がありません。

例えばユーザには「画像ロードボタン」と「画像編集ボタン」が提示されているとします。「画像ロードボタン」はユーザが指定したURLから画像をロードしてくるボタンです。「画像編集ボタン」はロードした画像に何か編集を加えるボタンです(モノクロに変換するなど、何でもよい)。仮にタイマを使っても、「画像ロードボタン」を押したあとロードが完了する前に制御がユーザに戻ってしまいます。その後すぐに「画像編集ボタン」を押されると、「画像編集ボタン」のイベントハンドラは既に画像が読み込まれていることを期待して読みに来ますが、実際は画像データはありません。

結局、対策としては、画像がロード済みかどうか(null)じゃないかどうか、使う前に毎回チェックして、ロードが済んでいなかったら何もしないっていうこと。それしかないのかなー。
なんとかSleep的な処理ができないかなーと思って疑似Threadライブラリ(そうめん?)なんかも試してみた。Threadが終了するまで待つことができるjoin関数が使えるかと思ったけど、Threadの終了を待てるのはThreadだけのようで、Threadではない実行部分で何かの処理を待機することはできない模様。
完全に手詰まりです。

ところで、Sleepが無い理由を自分なりに考えてみた。
Flexは基本的にイベント駆動型のアプリを作るためにあるはずなので、一つのイベントが全体をSleepさせるような処理を書くべきではない、ということなのだと思う。
でも、なんか、かゆい所に手が届かないむずむずというか、、、初めてSchemeを触った時に「破壊的代入を行わないプログラミング」が難しいパズルのようでどうしても頭に入ってこなかった時のような気持ち悪さ。
まー、修行が足りないってことですかね。

1 / 3123

Home

Search
Feeds

Return to page top