先日実施された、第42回シェル芸勉強会に参加してきたので、その復習。
今回は難しめにしたとのこと。

問題はこちら。最初に、問題等に使用するファイルをgitからcloneしておくといい。(といっても、ファイルは1個しかない)

git clone https://github.com/ryuichiueda/ShellGeiData

Q1

「正の整数の組(x, y, z)について、x + xy + xyz = 1234, x < y < zを満たす組み合わせを全て選べ」という問題。 数学オリンピックから出題されていた問題をちょっと改変した問題らしい(多分オリジナルはこれ)。

普通に計算させると終わらないので、↑のオリジナルと同じように最初の段階でちょっと頭を使う必要があるようだ。 上記の式は「x(1+y+yz) = 1234」となるのだけど、これを処理していくとfactorの結果として出力される数字が必ず含まれることになるから、それを利用する。

[REMOTE][ubuntu@test-ubuntu1804][~]
(`・ω・´) < factor 1234
1234: 2 617

上記の値と1を足した、3つの数字が必ず含まれるので、それを利用してブレース展開してやるといいようだ。
模範解答より短く書けなそうなので、解説付きで記述。

echo {1,2,617}_{1..1234}_{1..1234} # ブレース展開で組み合わせを出力
echo {1,2,617}_{1..1234}_{1..1234} | tr '_ ' ' \n' # _ => ' '(スペース), ' '(スペース) => 改行に置換
echo {1,2,617}_{1..1234}_{1..1234} | tr '_ ' ' \n' | awk '$1<$2&&$2<$3&&$1*(1+$2+$2*$3)==1234' # 各列に対して、条件に一致する内容か精査して出力

Q2

gitで落としてきたファイル「oji」の中にある絵文字を、全て💩に置換するという内容。「oji」の中身は、先日ぐれさんが作ってたojichatの出力みたいだ。

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

似たような処理をちょっと前にシェル芸botでやって遊んでたので、それを改変してやればいいようだ。
Perlでやってたのだが、残念ながらPerlだとRubyほど短く書けない。PerlのUnicode Propertiesだと絵文字をまるごと範囲指定出来ないので、「残したい文字種以外」といった指定方法が楽なのだけど、それでもかなり文字数を使う。
やはりRubyはこういう処理だと強いなぁ…。

# Perlの場合
cat oji | perl -C -ple 'use utf8;s/[^\p{BasicLatin}|\p{Katakana}|\p{Hiragana}|\p{Han}|\p{CJKSymbolsAndPunctuation}|\p{HalfwidthAndFullwidthForms}]/💩/g'

# Rubyの場合
cat oji | ruby -lne 'p $_.gsub(/\p{Emoji}/, "💩")'

Q3

1〜20までの出力から、素数の場合にランダムな値(同じ出力ではだめ)を出力させるという内容。 factorの出力から2列のもののみを利用することで対応できるので、awkのgetlineを使おうと思っていたところ、出力が変わらずに引っかかってしまった。

seq 20 | factor | awk 'NF==2{"echo-meme うんこ"|getline v;print $0,v}NF!=2{print}'

(解決策を自分で書いてて忘れてたのだが)awkでgetlineを使った場合、ちゃんと「close(cmd)」をしないと終了にならないので、それが必要だったのを忘れていたのが原因。
close(cmd)を行う際、実行するコマンドを変数に入れておいたほうがいろいろと都合がいいので、最終的な回答は↓のような感じになる。

seq 20 | factor | awk 'NF==2{c="echo-meme うんこ";c|getline v;close(c);print $0,v}NF!=2{print}'
[REMOTE][blacknon@bs-pub-ubuntu-03][~/ShellGeiData/vol.42]
(`・ω・´) < seq 20 | factor | awk 'NF==2{c="echo-meme うんこ";c|getline v;close(c);print $0,v}NF!=2{print}'
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

Q4

数字を打たずに「3」を出力しろという内容。難読化シェル芸系の問題だ。いろんなやり方が考えられるけど、とりあえず短いやり方だとこんなのだろうか。

echo ..|wc -m
wc -m<<<..

Q5

アルファベットを打たずにlsを実行しろという内容。こちらも難読化シェル芸系な問題だ。 文字コードを指定しての実行が簡単なので、それで対応する。

printf ls | xxd -a | cut -d' ' -f2 | grep -o .. | awk '{print "printf \"\\%o\" 0x"$1";"}' | bash | sed "s/^/$'/;s/$/'/" # 文字コードに変換
$'\154\163' # これで実行可能

ほかにも記号だけで回答するのとか、いろいろな方法があるのだけど、残念ながらそこまで難読化シェル芸を理解できてない(´・ω・`)。

Q6

ターミナル上でドット絵を生成して電車の電子案内板?(あの電車の上の方にある行き先書いてあるやつ)みたいなのを生成する際、飛行機の向きが絵文字だと逆なので、それを戻すという内容。 この辺になると疲れてた+あんまり電車好きじゃないのでモチベーションわかないという理由でちゃんとやれなかったので、模範回答だけ転載しておく。

●模範解答

echo ✈︎快特羽田空港 |sed -r 's/(.)./\1/' | \\
    textimg -F40|convert - -compress none pbm:- | \\
    tail -n +3|tr -d ' '|sed -r 's/.{40}/&\n/' | \\
    sed -r '1~2s/.*/echo & | rev/e' | xargs -n 2 | \\
    tr -d ' ' |sed -r 's/.{120}/&\n/'| \\
    sed -e '1~2s/0/■/g' -e '1~2s/1/🍀/g'  -e '2~2,$s/0/□/g' -e '2~2,$s/1/■/g'| \\
    xargs -n 2 | tr -d ' ' |textimg > a.png

Q7

seqとfactorで素数を生成して、桁が変わる場合は改行するという問題。 とりあえず愚直にawkでやる方式。

seq 1001 | factor | awk 'NF==2{print $2}' | awk 'BEGIN{ol=1}{l=length($1);if(l==ol){printf($1" ")}else{print $1};ol=l}'

最初はjqでやれるんじゃないか?とか思ったけど、ちょっと難しそう…(´・ω・`)

Q8

また電車系の問題。 電車の上の方に書いてある電子掲示板みたいなので、成田空港行きのを生成するやつ。

これもちょっと電車好きじゃないので、模範解答だけ書いておく。

$ echo "成田空港"|textimg -F40|convert - -compress none pbm:- | \\
    tail -n +3|tr -d ' '| sed 's/0/🍊/g;s/1/□/g' > a
$ echo For Narita-Airport |textimg -F15| \\
    convert - -compress none pbm:- |tail -n +3|tr -d ' '| \\
    sed 's/0/🍀/g;s/1/□/g' | \\
    awk '{for(i=1;i<=17;i++)printf "□";printf $0;for(i=1;i<=17;i++)printf "□";print ""}' > b
$ cat a b | textimg > a.png

最近ちょっと疲れ気味なので、記事書くのにえらく時間がかかってしまった。
今の仕事、日中結構頭を使うので疲れやすい傾向があると思うのだけど、それ+通勤長いのが理由だと思うので、早いとこ会社の近くに引っ越したいなぁ…(´・ω・`)