次ログ

次ログ

ゆるりと働いているSREの技術ブログのような何か。趣味の話も書く

Scrapboxにブログ移転します

こちらに移転します。以降こちらのブログは更新しません。 また移転ですが、と言われそうですが。

移転先

自分用の技術メモやTODOリストが中心のプロジェクト。更新頻度はめちゃくちゃ高い。 何かのイベントに参加したらレポートかいたりする。 ブログとして使うつもりはあんまりないけれど、本や映画の感想を残したりもしてる。

scrapbox.io

イラスト配布のプロジェクト。更新頻度はめちゃくちゃ低い。 配布用のイラストを配布可能な形にできたときだけ更新する。 落書きも載せるかもしれないけれど、落書きの頻度も低い。

scrapbox.io

サイトを分けた理由

イラスト配布に関する情報は、Scrapboxの別プロジェクトに分離するようにしました。 開発系とイラスト系だとジャンルが違いすぎるのと、更新頻度も全く違うのでわけるか、と。

僕は本職がソフトウェアエンジニアなので、技術ブログのほうを更新する頻度のほうが圧倒的に多いです。 イラストは本当に趣味で描いているだけなので、更新頻度はかなり気まぐれです。 なので、同じ情報を一つのサイトにまとめていても、イラストにしか興味ない人にとっては退屈だろうな、と思った次第です。

Scrapboxにした理由

Scrapboxにした理由としては、以下の通りです。

  • Scrapboxのが技術メモを残しやすい
    • もともとこのブログは技術メモを書こうと思って始めた
  • レスポンスがよい
  • 書き始めたらする公開されるので、書くことの敷居が低い
  • いろいろスクリプトで遊べる

ScrapboxはブログではなくWikiサービスです。 ブログサービスではないので、ブログによくあるような機能がなかったりします。 特に、コメント機能がありません。 初めはこれがすごく悩みました。

が、Twitterのアカウント載っけてるので、こっちに連絡もらえればよいかなぁと。 連絡するのにTwitterのアカウントが必要になりますが。

移転の変遷

こんな感じでブログを変えてきました。

  1. FC2ブログ
  2. はてなブログ
  3. GitHub Pages
  4. Scrapbox
  5. はてなブログ
  6. Scrapbox <-- ここ

すぐ書いてすぐ見れる状態が良いのだなぁと。

というわけで、失礼します。 何かあれば @jiro_saburomaru まで。

シェル芸bot環境につぶやいてきたジョークシェル芸をひたすら書き連ねる(その2)

シェル芸botに垂れ流したシェル芸を自分が忘れないようにメモするだけの記事。 前回のに比べると今回はしょうもないものが多い(前回のもしょうもない)。

その2だけれど続けるかどうかはわからない。

シェル芸

5000兆円欲しい

5000兆円でなくてもいいけれど、時間に対して給与がより多いほうが良い。

{分,時}とかってのはBashのブレース展開という記法。 カンマで区切られた全ての組み合わせパターンを生成できる。

要はこういうこと。

$ echo {a,b,c}_{1,2,3}\\n
a_1
 a_2
 a_3
 b_1
 b_2
 b_3
 c_1
 c_2
 c_3

ブレース展開はシェル芸で結構多用する。文字数をかなり削れるケースがあるため。 sedと組み合わせてこんなふうに置換式を書いたりできる。 -esedの式を空白で区切らず隣接させないといけない。

$ echo 'abc-abc-abc' | sed -e's/'{a,b,b,c}'/0/'
000-a0c-abc

これは以下と等価。

$ echo 'abc-abc-abc' | sed -es/a/0/ -es/b/0/ -es/b/0/ -es/c/0/

溶け出すうんこ

ネタ系、不気味。 💩を一旦「うんこ」に置換して、「うんこ」の文字のいずれかにマッチすると💩に置換する。 ようは💩を💩💩💩に置換していることと結果的には同じ。

ojichatメール誤送信

GitHub - greymd/ojichat: おじさんがLINEやメールで送ってきそうな文を生成するfakerでそれっぽい文章を作っただけ。 fakerでは偽名とか住所とかそれっぽいものを作れる。

cat << EOS

EOS

はヒアドキュメントというもの。複数行のテキストを表現できる。 $()で間にシェルの実行結果を埋め込める。

ojichat文字化け

またojichat系。iconvで文字化けさせた文字と文字化けしていない元の文字をランダムにとりだして ところどころ文字化けしている文章を生成する。

pasteでは元の文章と文字化けした文章を2列のデータとして結合している。

$ paste -d "" <(元の文章を1列で表現するシェル) <(元の文章を1列で且つ文字化けさせるシェル)

iconv -c -f CP932 -t UTF-8で文字化けを意図的に起こしている。

普通のLinux環境だとデフォルトの文字エンコーディングはUTF8だけれど ここでは元の文字エンコーディングをあえてCP932として指定している。

なので、UTF8の文字をCP932として無理やりUTF8に変換している。-cでは文字の変換に失敗しても無視する。

$ n=$(shuf -e 1 2 -n 1); echo "$line" | sed -E 's@(.)(.)@'\\$n'@g'

ここでは変数nの1か2の値をセットし、sedの後方参照でどちらの文字を出力するかに指定している。 (.)(.)正規表現での文字のグルーピングの表現で、それぞれ任意の文字が1つずつ格納されている。 1文字目を取得するときはsedの置換式で\1を指定する、2文字目なら\2である。

なので、1/2の確率で文字化けした文字が取り出されるので、文字化けした文字と普通の文字を混ぜることができている。

でかい文字

textimgで文字をそのまま画像にして出力して ImageMagickでPGM画像に変換している。

PGMは数値を画像のピクセルと色に見立てて表現するテキスト形式の画像フォーマット。 色の数値部分のみ取り出して置換して任意の文字に置き換えるというアプローチをしている。

lolcatは色を付けるコマンド?よく知らない。最終的にまたtextimgで画像に変換して終了。

シャブキメ

ネタ系。ブレース展開の組み合わせとtrでの置換でテキストを表現。 短く書けたので満足。

元はこれ

btnmaker.me

色が移動

awkで1文字ずつ文字をエスケープシーケンスで囲って出力するだけ。 テキストの折り返しには tee >(tac) を使用。

teeはパイプ元の入力を標準出力に出しながらファイルにも出力できるコマンド。 サーバ作業のときにはよくお世話になる。 今回はファイルではなくコマンドのtacに渡している。 >(コマンド)でコマンドに渡せる。

tacは入力ストリームを行で逆順に出力する。catの逆なのでtac。

難読化16進数date

dateコマンドを難読化して実行。 bashでは$'\U16進数'で16進数をそのコードポイントに該当する文字に変換して出力する。 たとえば あ を16進数で出力するには $'\U3042' と書く。

あとは数値の部分をどうやってわかりづらくするか、に$$を使用した。 $$は難読化シェル芸で頻出の、プロセスIDを取得する特殊変数。 プロセスIDはコマンドの実行ごとに変化するが、$(($$/$$))としたら同じプロセスIDで割ってるので 1が得られる。あとはそれを組み合わせてほしい値を取り出してる。

__=(.{,,,}{,,,}{,,,});___=(.{,,,}{,,});

の部分は僕もなんでこんなこと書いたのが思い出せなかった。 echo ${#__[@]} してみたら64が得られたので、多分この辺の数値が欲しかったんだと思う。 ${#変数名[@]}とやると配列変数の長さを取得できる。前述のでは、.文字をブレース展開で複製して 64個の配列要素にしてるっぽい(書いた本人が忘れてる)。

ファイル名アスキーアート

toiletコマンドの結果をファイル名に使用するというアプローチ。 元はwhileでループしてたけれど、もっとスマートに書きたくていろんなテクを使ってみた。

eval

evalはbashのコマンド列を評価する。ここにブレース展開とセミコロンを入れることで、 複数のコマンドの実行を短く実現している。

eval 'toilet '{ほ,ん,ば,ん}';'

このコマンドは以下のコマンドと等価である。

(toilet ほ; toilet ん; toilet ば; toilet ん;)

単純にtoiletをセミコロンで区切って実行した場合だと、それぞれのコマンドの実行結果をパイプ先に渡せないが evalとブレース展開で実行するシェルはサブシェルとして1つにラッピングされてるみたい。 今回みたいに、セミコロンで区切った複数のコマンドの実行結果を全てパイプ先に渡せている。

ようはこういうこと。

toilet ほ; toilet ん; toilet ば; toilet ん; | nl # 構文エラー
(toilet ほ; toilet ん; toilet ば; toilet ん;) # OK
eval 'toilet '{ほ,ん,ば,ん}';' | nl # OK

lolcat

特に言うことはない。色を付ける

nl

普段nlコマンドなんて全く使わないけれど、数値出力のフォーマット指定と区切り文字の指定ができることを知った。 これで3桁、0埋め、区切り文字にアンダースコアという指定になる。

nl -w3 -nrz -s__

sed

最後、テキスト全体をtouchのコマンド文字列に置換してeでそのままシェルのコマンドとして実行。

sed -E "s/.*/touch '\/__&'/ge"

ようはこんな感じの文字列に置換している。

touch '/__001__ほげほげ〜〜〜'
touch '/__002__ほげほげ〜〜〜'
touch '/__003__ほげほげ〜〜〜'

中央寄せアニメーション

ネタ系。特に書くことがない。普通のgrep awk。出力している文章は、最近僕がハマっている 「クトゥルフ神話TRPG」の書籍に登場する一文。

嘔吐

ネタ系。echoをgrep awkしてキングウンコに連結してるだけ。特に書くことない。

ホクホクのイモ

いかに触発されてやった。

qiita.com

ホクイモ からランダムで2文字取り出すのを2回実行し、実行結果を正規表現の後方参照で取り出して出力した。

PowerWord

ネタ系。こちらも触発された系。 自前のalignコマンドでテキストを左右中央寄せして 任意の文字数の位置まで正規表現で置換してエスケープシーケンスをつけただけ。

Windows XP ?

Windows XPの画像を再現したかったけれど、再現度が低くてよくわからない。

横切るウンコ

seqの値をパディングの回数として使用してsedでテキストの先頭に埋め込んでいるだけ。 最後に tee tacでひっくり返す。

まとめ

画像系、アニメーション系が多かった。 textimgを自作してから画像系シェル芸をよくやるようになった。 最近はネタ切れになってしまった。その3記事は書かないような気がする。

Vimプラグインのsuper_unko.vimを作った

Vimをガッツリ使うようになってかれこれもう3,4年になります。 プラグインでガッツリカスタマイズして使っていたものの、 プラグインを自作するには至りませんでした。

が、少し時間に余裕があったので簡単なVimPluginを自作しました。

作ったもの

Vimでクイズをするためのプラグインです。 使い方はREADMEを参照。

github.com

作った理由

VimScript、VImPluginの勉強が目的です。 なのでプラグインを作るときのお作法の確認や 配布できるようにするのに何を意識する必要があるのか、とかの確認が主目的です。

クイズの内容はすごくしょうもないですし、クイズの数もほとんどありません。 Vimに乱数生成の機能がないので、クイズの問題選択もランダムではありません。

しかしながら、vim-plugでインストールできるようにもなりましたし、 helpも書いて一応最低限の体裁を整えることができました。

よって、当初の目的は無事達成しました。

実際に作りきってみて、変数のスコープやVim特有の変数定義のしかた、 関数とコマンドの違い、関数の呼び出し方、ファイル分割の仕方、 ヘルプの書き方などなど、いろいろな発見がありました。 これで次プラグインを書くときはこのリポジトリを参考にすればよいので 開発がはかどりそうです。

作ったもの2 (super_unko)

Vimプラグインを1つ完成させたけれど、今Vimに特段欲しいと思う機能はありませんでした。

やることないな、と思っていたのですがsuper_unkoをVimPluginにしたいな、と唐突に思いつきました。

早速行動に起こして、リポジトリを作りました。 少しだけコマンドも実装しました。

github.com

これでsuper_unkoがVimからも使えるようになった。 (ただし使いみちがない)

余談

こういうプラグイン作成はこれからも続けるだろうなぁ、と思ったので VimPluginの雛形を作成するためのスクリプトをささっとBashで書いた。

実は同じようなものを過去にPythonで書いていた。

github.com

存在を完全に忘れていたのと、この程度の処理ならPython使うほどでもなかったのでBashで書き直した。

以上です。

V言語でライフゲームした+雑感

V 0.1.11です。 なんとなく思い立ってライフゲームしてみました。

qiita.com

V言語のリポジトリが公開される前情報だけの時点ではすごくいろんな方から注目を集めていた感じですが リポジトリが公開されてみれば未実装の機能とバグの温床で日本では一気に話題に上がらなくなった感じがします。 TwitterでV言語って検索してもほとんどヒットしない。

少し標準ライブラリの関数使ってみて、いきなりSegFaultでクラッシュしたり 乱数生成したら常に同じ値を返していたり(ただし今は修正済み)、 標準APIドキュメントに関数IFのみで説明が存在しないなど未完成さがすごく目立つ。

しかしながらGitHubのスター数でいえば登場して間もないのにすでに9000スター。 僕が最近触ってるNimの8000を一瞬で上回っていて、この伸び具合はなんなんだろう。 今後に期待のスターなのか、すごくPRが上手なのか。

まぁV言語のうたう機能全てを本当に実装したらとてもよい言語になりそうだとは思います。 確かにコンパイルは早いですし、コンパイラ自体のビルドも高速。コンパイラ自体も軽量です。 クロスコンパイルもサポートしてるらしいです。 ネイティブGUIを標準サポートでしたらGoがあまり力をいれてないGUI系が使えるようになるのですから。

とはいえコンパイルの高速具合は機能が少ないからコンパイルが早いだけ、かもしれない。 てかV言語自体はC言語へのトランスコンパイラに過ぎないのでコンパイラのサイズが小さいとも考えられる。 結局実行可能バイナリへ変換するのはCコンパイラ依存なわけですし・・・。

同じくC言語へトランスコンパイルして実行可能バイナリを生成する系の言語のNimですが こちらのほうがかなり機能も多く安定性もあるにもかかわらずファイルサイズはVよりも少なかったです。うーん?

$ ls -lah /usr/local/bin/v /home/jiro4989/.nimble/bin/nim
-rwxr--r-- 1 jiro4989 jiro4989 264K  6月 16 07:10 /home/jiro4989/.nimble/bin/nim
-rwxrwxr-x 1 jiro4989 jiro4989 349K  7月  3 23:55 /usr/local/bin/v

とりあえず、しばらくは静観。 少なくとも今はまったく実用段階ではないという感触です。 今後に期待です。

toiletコマンドのDockerイメージを作った

ジョーク系コマンド、toiletのDockerイメージがなかったので作った。

hub.docker.com

toiletコマンドとは

toiletコマンドについては以下の記事が参考になる。

qiita.com

qiita.com

作った経緯

Unkontributorsの一人として、super_unkoのDockerfileを作った。

github.com

作るに際して、Dockerのベースイメージを何にするか考えました。 一番簡単に作れるのはcowsayやtoiletをaptでインストールできるubuntuイメージをベースにすること。 しかしながら、それだと余計なものが入ってしまい、イメージが巨大になってします。

なので、イメージの軽量化目的でalpineベースで作成することにしました。

super_unkoでやったこと

alpineで作成するにあたって、toiletコマンドを動かせるようにするのに大変苦労しました。 理由としては、toiletコマンドのリポジトリのドキュメントに依存ライブラリやビルド方法について何も記載がなかったからです。

なのでビルドが失敗しては不足するものを追加してをひたすらやってなんとかビルドできるようになりました。 ほんとこういうときはドキュメントが大事だなぁと感じた次第です。

ちなみにUbuntuベースで作ったものとalpineベースで軽量化を意識して作ったイメージのサイズは以下のようになりました。 試みとしては十分に成功しました。

ベースイメージ イメージサイズ
Ubuntu 195MB
Alpine 68.4MB

軽量化のためにやったことは、不要なパッケージを残さないようにすることだけです。 以下のような具合。

FROM alpine:3.9 AS build-stage

RUN apk --no-cache add git bash perl make automake autoconf pkgconfig gcc musl-dev libcaca-dev figlet \
# その他もろもろの処理 ...

FROM alpine:3.9 AS exec-stage
RUN apk add bash perl libcaca-dev
COPY --from=build-stage /usr/local/bin/* /usr/local/bin/
COPY --from=build-stage /usr/local/src/toilet/fonts/* /usr/local/share/figlet/

バイナリの生成のためのbuild-stageで必要なツール群をapkでインストールしてビルドし、 コマンド実行のためのツールのみを残すexec-stageに必要なもののみCOPYするというアプローチです。 これだけで100MBほど軽量化できました。

Ubuntuベースで作ったイメージだとbashperl、make、gccとかは特にインストールしなくてもよかったので 多分そのへんの細かいツールが最初から含まれているからサイズが巨大なんでしょうね。

toiletでやったこと

で、super_unkoについてはそれで良かったんですが せっかくなのでtoiletだけ使えるようにしたイメージも作ってしまおうと考えました。

元のtoiletリポジトリはすでに更新が止まってるみたいだったんで PR送っても無駄でしょうし、自分で作ってDockerHubに登録してしまっておこう、ということです。

いわゆる昔ながらの手法のconfigureMakefileを生成してmakeするタイプのプロジェクトでしたので 余り経験がなかったのもあり、エラーを追跡するのが非常に大変でした。

まぁ、良い経験になりました。

第42回 シェル芸勉強会振り返り

まえがき

2019/06/15に「jus共催 第42回BLACK HOLEシェル芸勉強会」へ参加してきたのでその振り返り。 今回の名前は前回のブレース展開と違って普通の名前だった。

いわくここでいうBLACK HOLEは「アトランティスの謎 42th」を指すものだったらしい。 僕はアトランティスの謎というゲームを知らなかったけれど、ニコ動の何かの動画で 無限に落下するシーンを見たことはあった。

シェル芸の様子はこちら。

togetter.com

問題

Q1 正の整数の組(x, y, z)について、x + xy + xyz = 1234, x < y < zを満たす組み合わせを全て選んでください

競技プログラミング的な問題。普通に3重ループで実装したら計算量が 12343 になってとんでもないことになる。 例えば以下のような。(僕の回答)

for x in {1..1234}; do
  for y in {1..1234}; do
    for z in {1..1234}; do
      n=$((x + x*y + x*y*z))
      if [ $n -eq 1234 ]; then
        echo "x=$x y=$y z=$z"
      fi
    done
  done
done

一応この回答でも全然終了しないけれどそのうち計算は終了する。 けれど、それではこの問題を用意した意図に応えられていない。

x + xy + xyz == 1234 and ( x < y < z ) というこの問題、ぱっと問題を見た時ではわからなかったけれど、これは普通の数学の問題だった。

x + xy + xyz == 1234を式変形するとx(1 + y + yz) == 1234と等価になる。

これを更に式変形するとx(1 + y(1 + z))になる。

これはx * N == 1234と言い換えられるが、このNが何通り考えられるかを考える。 この1234を素因数分解すると、次のようになる。

% factor 1234
1234: 2 617

このことからxとNの組み合わせは次の通り考えられる。

  • x == 1 のとき N == 1234
  • x == 2 のとき N == 617
  • x == 617 のとき N == 2
  • x == 1234 のとき N == 1

しかし、前提条件として(x < y < z)が与えられているため、最終的に次のようになる。

  • x == 1 のとき N == 1234
  • x == 2 のとき N == 617

この時点で総計算量を比較してみる。

  • 1234 x 1234 x 1234 = 1879080904 (18億7908万)
  • 2 x 1234 x 1234 = 3045512 (304万)

304万オーダーならまぁ普通に計算できる計算量なので、僕の最初に考えたシェルは次のように修正できる。

for x in {1..2}; do
  for y in {1..1234}; do
    for z in {1..1234}; do
      n=$((x + x*y + x*y*z))
      if [ $n -eq 1234 ]; then
        echo "x=$x y=$y z=$z"
      fi
    done
  done
done

awkを使うともっと短くかける。

echo {1,2}" "{1..1234}" "{1..1234}"\n" | awk '$1 < $2 && $2 < $3 && $1 + $1 * $2 + $1 * $2 * $3 == 1234'

Q2 次のファイルの文章内の絵文字を全て💩に変えてください

$ cat oji
あれ(^_^;さのチャン、朝と夜間違えたのかな❗❓⁉俺はまだ起きてますよ〜😃 ちょっと電話できるかナ( ̄ー ̄?)⁉天気悪いと気分もよくないよね😱じゃあ今日は会社休んで俺とデートしヨウ💕ナンチャッテ🎵(笑)😘

僕のはじめの回答はこんなかんじ。あらゆる絵文字に対応できる方法が思いつかなくて、明らかに手抜きな回答になった。

cat /ShellGeiData/vol.42/oji | sed -E  "s@$(cat /ShellGeiData/vol.42/oji | grep -o . | sort | head -n 9 | tr '\n' '|')z@💩@g"

なにをやっているかというと、sed拡張正規表現の文字列を作っている。なんとなく sortして戦闘の文字列を確認したらいい感じに絵文字が先頭に偏っていたのでそれを9 文字決め打ちで取り出している。

% cat ShellGeiData/vol.42/oji | grep -o . | sort | head -n 20
❗
❓
⁉
⁉
😃
😱
💕
🎵
😘
 
(
;
?
^
^
_
、
 ̄
 ̄

これを正規表現のORでつなぐ。

% cat ShellGeiData/vol.42/oji | grep -o . | sort | head -n 9 | tr '\n' '|'
❗|❓|⁉|⁉|😃|😱|💕|🎵|😘|

すると正規表現の最後にORだけが残ってしまう。 めんどくさかったのでもとの文字列に出現していなかったzを付け足した。

% echo "s@$(cat ShellGeiData/vol.42/oji | grep -o . | sort | head -n 9 | tr '\n' '|')z@💩@g" 
s@❗|❓|⁉|⁉|😃|😱|💕|🎵|😘|z@💩@g

これをsed -Eに渡してやれば、絵文字をすべて💩に置換できる。 かなり雑だし問題しかない。 正しい回答はnkfawklength関数を使う方法。

上田先生のブログより引用。

$ grep -o . oji | LANG=C awk '{printf length($1)==4?"💩":$1}' | awk 4

Q3 (要約)素数のときに任意の値を出力してください

2: きつねうどん
3: ブラウンソース定食
4:
5: 鉄皿ブラウンソースハンバーグセット
6:
7: きつねうどん ミニプレミアムおろしポン酢牛めしセット
8:
9:
10:
11: 鉄皿ブラウンソースライス
12:
13: 担々うどん(プレミアム牛肉使用)
14:
15:
16:
17: とろたまうどん ミニポン酢ポン酢牛めしセット
18:
19: 豚カルビ丼
20:

僕の回答(ただしゴミが残ってるし、間違ってる)

% paste -d : <(seq 20) <(seq 20 | while read i; do factor $i | cut -d : -f 2- | awk -F " " '{print NF}'; done | sed -E 's@^1$@'"$(ojichat)"'@g')
1:0
2:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
3:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
4:2
5:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
6:2
7:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
8:3
9:2
10:2
11:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
12:3
13:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
14:2
15:2
16:4
17:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
18:3
19:吏花ちゃん、愛しいなぁモウ😘🎵(^з<)こんなに可愛く💕😄(^з<)なっちゃったら天使みたいでオジサン困っちゃウヨ(・_・;(^_^;
20:3

まず、ループしてfactorに引数としてわたして素因数分解する。

% seq 20 | while read i; do factor $i;done
1:
2: 2
3: 3
4: 2 2
5: 5
6: 2 3
7: 7
8: 2 2 2
9: 3 3
10: 2 5
11: 11
12: 2 2 3
13: 13
14: 2 7
15: 3 5
16: 2 2 2 2
17: 17
18: 2 3 3
19: 19
20: 2 2 5

この時、素数のものは:で区切られた右側の文字は1つしかないはず、と考えた。 よって、:で区切った2フィールド目の文字列のみを取得し、さらに空白区切るのフィールドの数を数えれば、素因数の数が取得できる。

% seq 20 | while read i; do factor $i | cut -d : -f 2- | awk -F " " '{print NF}'; done
0
1
1
2
1
2
1
3
2
2
1
3
1
2
2
4
1
3
1
3

あとは1だけをsedで置換すれば一応僕の回答にはなる。間違っているけれど。

% seq 20 | while read i; do factor $i | cut -d : -f 2- | awk -F " " '{print NF}'; done | sed -E 's@^1$@'"$(ojichat)"'@g'
0
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
2
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
2
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
3
2
2
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
3
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
2
2
4
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
3
えみこ、愛しいなぁもウ😃♥ (^o^)可愛すぎてボクお仕事に集中できなくなっちゃいそうだよ(◎ _◎;)どうしてくれるンダ😃✋
3

何が間違っているか、というと。

  1. 余計な数字が残っている
  2. ojichatの実行結果が毎回同じになっている。

この回答のだしかたが良くなかったのもあるけれど、この回答に会えて修正を入れるなら次のようにすればこの問題の解になる。

% paste -d : <(seq 20) <(seq 20 | while read i; do factor $i | cut -d : -f 2- | awk -F " " '{print NF}'; done | sed -E 's@^1$@ojichat@ge; s/^[0-9]+$//g')
1:
2:えいはチャン、可愛らしいネ😍😃♥ 可愛すぎてオジサンお仕事に集中できなくなっちゃいそうだよ(・_・;(T_T)(◎ _◎;)^^;どうしてくれるんダ😚(笑)❗
3:おはよー!チュッ(^з<)早く会いたいナ(^_^)😍❗
4:
5:センリチャン、お早う(^_^)😍😆センリチャンと一緒に今度ランチ、したいなァ(^o^)💗(^_^)風邪ひかないようにね😚(^_^)😆😘
6:
7:風邪ひかないようにね💕💗オイラはももきちゃん一筋だよ🤑✋
8:
9:
10:
11:美佐穂チャン、オッハー(^_^)(^o^)美佐穂チャンにとって素敵な1日になりますようニ😄
12:
13:今日も大変だったんだネ(-_-;)よく頑張ったね💕えらいえライ😄😃☀ 
14:
15:
16:
17:みゆきちゃん、可愛らしいね(^з<)(^_^)こんなに可愛く(^o^)😃♥ なっちゃったらお姫様みたいでオジサン困っちゃウヨ(・_・;(-_-;)😱( ̄Д ̄;;
18:
19:帆夏チャン、そっちも快晴なのかな😜⁉️水曜日は仕事〜❓( ̄ー ̄?)😜⁉️よく頑張ったね🎵(^_^)えらいえらイ(笑)😘
20:

修正したのはここ。

sed -E 's@^1$@ojichat@ge; s/^[0-9]+$//g'

いきなりojichatの実行結果をsedの置換式に埋め込むのではなく、ojichat自体を埋め込んでeで実行するようにした。 そのあと数字だけ残っている行を消す置換をすることで完成。

Q4 数字を打たずに3を出力してください

難読化シェル芸。僕の回答は下記。

echo $(( $(echo a | grep x)$? + $(echo a | grep x)$? + $(echo a | grep x)$? ))

grepで検索にマッチするものが存在しなかった時、終了コードは1になる。 それを$?で取得してbashの算術演算で加算している。

ただ他の方の回答ではより難読化しているものがあった。 面白かったのは以下。

% echo $(( $$/$$ + $$/$$ + $$/$$ )) 
3

$$はプロセスIDである。プロセスIDをプロセスIDで割ると当然1になる。あとはそれを加算している。

あとは僕が思いついたしょーもない回答。

$ unko.tower | wc | sed -E 's/|/ /g' | awk '{print $NF}'
3

なんなのかというとunko.towerの文字の数を数えたらたまたま一番最後の文字が3だったのでそれを取得している。 sedですべての文字を空白で区切り、awk$NFで一番最後の文字を取得した。

Q5 アルファベットを打たずにlsを実行してください

これも難読化。 パス補完の機能を使えばいいんだろうというのはわかったが、「アルファベットを使わずに」というのはわからなかった。 回答としてはこうなるらしい。

% echo /???/??
/bin/cp /bin/dd /bin/df /bin/ed /bin/ip /bin/ln /bin/ls /bin/mt /bin/mv /bin/nc /bin/ps /bin/rm /bin/sh /bin/ss /bin/su /dev/fd /etc/hp /etc/i3 /etc/pm /sys/fs


% __=(/???/??); ${__[7]}
oji

これはなるほど〜となった。 パス補完を配列として変数に追加して、決め打ちで配列のインデックスを指定して取得する、という。 lsが何番目に位置するかは環境によって変わるので、そこは適宜読み替える必要がある。

Q6 飛行機アイコンのみを左右反転させる

まさか僕が作ったtextimgというコマンドが問題の中で使われると思っていなくて驚いた。 なお問題は解けなかった。

問題の回答にのためにいろんな方がtextimgをインストールしようとして苦戦していたのが印象に残った。 インストールに時間がかかっていたようで、Go自体のインストールに時間がかかっていたのだと思われる。

あとは一応単体で動作する実行可能バイナリも配布していたが、絵文字とかの描画を可能にするにはさらに環境変数とかフォントを整える必要があるので おそらくそのあたりで躓いたのかなぁと考えている。

一応整備するべき環境変数についてはREADMEには書いておいたが、いきなりそれをやれというのはやはり難しいので 手軽に試せるDockerfileも用意しておこうと思った。 (Dockerを使えるようにするのが難しいとかはまた別の話)

Q7 素数の桁が変わる直前のところで改行を入れてください

$ seq 1000000 | factor | awk 'NF==2{print $2}' | tr \\n ' ' 
ここからパイプをつなげて、。つまり、桁数ごとに素数を1行に並べて出力してください。なお、awk、perl、rubyなどのプログラミングできるコマンドやbashのforやwhileなどの制御構文を用いて出力できた場合は、それらを使わずに出力してみてください。sedは可とします。

次のように確かめるとデバッグしやすいです。

$ seq 1000000 | factor | awk 'NF==2{print $2}' | (解答) | awk '{print $1,$NF}'
2 7
11 97
101 997
1009 9973
10007 99991
100003 999983

僕の回答は次の通り。数が決め打ちなので汚い。

$ seq 1000000 | factor | awk 'NF==2{print $2}' | tr \\n ' ' | sed -E 's/ ([0-9]{2}) ([0-9]{3})/ \1\n \2/g; s/ ([0-9]{3}) ([0-9]{4})/ \1\n \2/g; s/ ([0-9]{4}) ([0-9]{5})/ \1\n \2/g; s/ ([0-9]{5}) ([0-9]{6})/ \1\n \2/g' | awk '{print $1, $NF}'
2 97
101 997
1009 9973
10007 99991
100003 999983

ようは数字の連続する長さが切り替わるタイミングで改行を入れる、というアプローチ。 sedでいい感じにやる方法が思いつかなかった。

他の方の回答でgrepを使うのがすごくきれいでよかった。

seq 1000000 | factor | awk 'NF==2{print $2}' | tr \\n ' ' | grep -Eo -e'(([0-9]{'{1..6}'} )*)'

Q8 これをなるべく忠実に作ってみてください。

このあたりの画像系のシェル芸についていけてなくて遅れを感じている。

LT会

今回のLT会は名言の宝庫だった。 名言だと思ったもの。

  • くだしンス
  • ふつうの難読化
  • これはdateコマンドです
  • 難読化シェル芸のアンダーバー派
  • 好きなVimVim
  • Tab補完は軟派
  • 娘のChangeLog

まとめ

ということで今回の問題の僕の正答率は 3 / 8 。今回は難しかった。 今回は難読化、画像、数学とバリエーション豊かだったと感じた。

前回のsort系は得意なほうだった。 逆に今回は未知の問題ばかりだったので苦戦したが 解きほぐしてみればなるほどな、というものばかりだった。

Linux環境のRPGツクールMVで日本語入力できなかった原因を特定した

ちょっと前からLinux環境のRPGツクールMV(Steam版)で日本語入力ができなくなっていた。 昨日気分転換にプライベートPCのOSをManjaroLinuxからLinuxMint Cinnamonに変更して、 ツクールも入れ直して動作確認したらやっぱり動かない。

そもそもなんでこれ動かないんだろう数年前は動いていた気がするのになぁ・・・ と思い、本腰いれて原因を調査した。

ここではどういう過程で調査したのかを順に記録する。

前提情報

まず、僕は日本語入力のIMEの仕組みとかを何も知らない。 Linux環境で日本語入力を可能にするためのfcitxだのibus-mozcだのも Webの知識をコピペして設定して動かしている。 よって何もそのあたりの細かい仕様について知らない。

知らないなりに色々仮説を立てて調査したので トンチンカンなこと言っている可能性は大いにあります。

調査

そもそも日本語入力できるのか

ツクールMVの文章入力の画面で全角半角変換のキーを入力しても反応しない。 アルファベットはそのまま普通に入力できた。

しかしながら、エディタやブラウザなどで日本語を入力してから コピペで貼り付けたら日本語を入力できた。 よって日本語を入力できる環境自体はあると考えた。

キーボードレイアウトをUS配列から日本語配列に変更

僕はHHKBのUS版を使っているので、キーボードレイアウトもUSに変更している。 日本語変換もfcitx + ibusで右altと左altで日本語英語を切り替えるようにしている。 この設定が何か問題になっているのでは、と考えた。

例えば、Altキーで日本語に変換しようとしてメニューバーの方にフォーカスを奪われて いたりするかもしれない、と考えたためである。

試しで日本語配列に変更し、素直に全角半角キーで変更するように設定を戻してみたが、 結果は変わらなかった。

類似情報がないか調べる

だいたいこういうのは他の人も詰まっているだろう、と思ってGoogle検索や Steamのフォーラムで色々調べてみた。

「SteamはGoogleIMEでは日本語入力できないけれど、MS IMEなら入力できる」 みたいな情報も見つかりはしたが、ツクールには逆に全くそれっぽい情報が見つからなかった。

起動オプションを疑う

Steamからゲームを起動する時、ゲーム起動時にオプションを渡すことができる。 上級者向けの機能で、僕は全く使っていない。名前だけ知っていた。

起動時のオプションとかでIMEオフみたいなのがもしかしたらあるかも、と思い プロセスの起動オプションを調べてみることにした。

% ps aux | grep -i rpg
jiro4989  5530  0.0  0.0   4644   272 ?        S    13:10   0:00 /bin/sh -c '/home/jiro4989/.steam/steam/steamapps/common/RPG Maker MV/RPG Maker MV.sh'
jiro4989  5532  0.0  0.0   4644   268 ?        S    13:10   0:00 /bin/sh /home/jiro4989/.steam/steam/steamapps/common/RPG Maker MV/RPG Maker MV.sh
jiro4989  5537 12.0  2.0 4020776 245376 ?      Sl   13:10   0:02 /home/jiro4989/.steam/steam/steamapps/common/RPG Maker MV/RPG Maker MV
jiro4989  5550  0.0  0.2 287016 31356 ?        S    13:10   0:00 /home/jiro4989/.steam/steam/steamapps/common/RPG Maker MV/libexec/QtWebEngineProcess --type=zygote --no-sandbox --lang=C

すると、「QtWebEngineProcess」というプロセスが目に止まった。 ツクールMVはQtで作られている可能性があると考えた。

エディタ側のライブラリを調べる

IMEを実装したことないので想像で話すが、 いろんな言語に対応する必要のあるIMEなんて僕ならとても実装したくない。 既存でライブラリがあるなら絶対使う、と思ったのでライブラリ側の名前で情報を探す。

最初に想像したのはNW.js。 ツクールMVのゲームはNW.jsで動く。

ただし今回問題になっているのはツクールMVの生成されたゲームではなくエディターの方なので NW.jsは調べても意味ないだろうなと考えた。

前述のQtらしきプロセスのこともあったので、ツクールMVとQtについて調べたら やはりQtで作られていることがわかった。

RPGツクールMV - Wikipedia

Qtといえばクロスプラットホームで動作するGUIツールキットなので、 Linux, Mac, Windowsで動くのも納得。 日本語入力もQt側でよしなにやっていると考えたのでQtの日本語入力について今度は調べることにした。

Qtのライブラリを調べる

とりあえず雑に「Qt 日本語入力」で調べたところ、まっさきに以下の記事がヒットした。

自作QtアプリやQtCreatorで日本語入力ができない問題の解決法

この記事の中の以下の記載が目に止まった。

libfcitxplatforminputcontextplugin.soがないためらしい。

fcitx と書いてあるので、もしかしたらこれと近い名前のInputMethodプラグインをツクールMVも使っているのでは、と考えた。 以下のコマンドで調査した。

% pwd
/home/jiro4989/.steam/steam/steamapps/common/RPG Maker MV

% find . -name "*.so" | grep plugin | grep -i -e ibus -e fcitx -e anthy
./plugins/platforminputcontexts/libibusplatforminputcontextplugin.so

「libibusplatforminputcontextplugin.so」というすごくそれっぽい名称のファイルが見つかった。 他に同様のファイルがないかを念の為確認。

% ls -1 plugins/platforminputcontexts
libcomposeplatforminputcontextplugin.so
libibusplatforminputcontextplugin.so

これだけ見るとibus以外のInputMethodに対応していないように見える。 僕の環境ではfcitx-mozcを使用しているので、これだと僕の環境で日本語入力できないのも 納得できた。

ということで次は日本語入力をfcitx-mozcからibus-mozcに変更して検証することにした。

日本語入力をfcitx-mozcをibus-mozcに変更

僕のPCの環境はAnsibleである程度構築を自動化している。 fcitx-ibusの環境構築もある程度自動化していた。

今回の調査に際して、以下のように変更を加えた。

https://github.com/jiro4989/setup/commit/75b07d0a3e70de8d50c2ee32d2ac2fbc1c499029

他の設定は以下の記事を参考にした。

LinuxMint 19: 日本語入力の設定をする

日本語入力できるようになった

ということで、紆余曲折を経て無事以下のようにLinux環境で日本語入力できる状態になりました。

まとめ

Linux環境でツクールMVで日本語入力できなかったのを解決する過程を説明しました。 僕と同じ問題に直面している人の助けになれば幸いです。