2017年2月13日

第27回シェル芸勉強会参加報告

2017-02-11(土)に開催された、第27回シェル芸勉強会(正式名称:jus共催 第9回初心者満足度ナンバーワン(当社調べ・調べてないけど)シェル勉強会/第27回sedこわいシェル芸勉強会)に参加しました。
ただ、在住地の関係で直接会場へ伺うことは出来なかったため、Youtubeで配信してくださったライブ中継を利用して、遠隔で参加しました。

勉強会は、午前と午後の2部構成でした。
午前は、シェルに関する勉強会で、シェルの基礎を学ぶ内容でした。
午後は、シェル芸勉強会で、シェル芸力を付けるための問題を解きました。

以下、勉強会の詳細を記します。


実行環境

  • Arch Linux 4.9.6-1-ARCH

  • GNU bash 4.4.11

  • GNU coreutils 8.26-1

  • GNU findutils 4.6.0-2

  • grep (GNU grep) 3.0

  • sed (GNU sed) 4.4

シェルに関する勉強会

黒い画面と戯れよう

USP友の会 鳥海秀一さんによる、黒い画面と戯れようでした。

ncurses に含まれる、各種端末制御コマンドを使って、端末の動作を学ぶという内容でした。
個人的には、以下の内容が気になりました。

  • 文字はゲシュタルトであり、フォント等を変えることで、文字が持つ情報以上の何かを伝えることができる。

  • bashは、黒い画面をファイルとして扱っている。
    → ttyコマンドで、現在開いている画面ファイルを確認できる。

  • エスケープシーケンスは、黒い画面を操作するための、特殊な文字列。

  • tput でカーソルを移動できる。
    → 自分の端末でやると不便なので、 > /dev/pts/x として、他人の端末を動かそう!

  • エスケープシーケンスで、sinカーブが描ける(白目

シェル芸入門 日常会話編

USP友の会 石井久治さんによる、シェル芸入門 日常会話編でした。

シェル芸の考え方から始まり、シェル芸の基礎文法としてシェル( bash )の機能解説、そしてシェル芸の頻出単語(コマンドの組み合わせ)と、初心者にも易しい内容でした。
…​のはずが、途中で講師の石井さんが熱中しすぎて、難易度が一気に跳ね上がる場面もあったりw

第27回シェル芸勉強会

問題文および模範解答は、以下のURLから。
https://blog.ueda.asia/?p=9283

問1

偶数・奇数番目の文字を大文字に変換する問題。

お馴染みの grep -o . で縦にした後、偶数・奇数行のみを大文字に変換していく。
ここで、偶数・奇数行のみ処理をおこなうため、 sed のアドレスに倍数行指定の ~ (GNU拡張)を用いる。
また、本回は「 sed は置換だけじゃない!」というテーマだったので、出来るだけ s コマンドは使わない方針で、 y コマンドを使ってみた。
大文字変換した後は、お決まりの xargs で横に戻して、最後に tr で余分な空白を消すだけ。

#!/bin/sh

echo abcdefghijklmn                           | # 文字列の出力
grep -o .                                     | # 列行変換
sed '2~2y/abcdefghijklmn/ABCDEFGHIJKLMN/'     | # 偶数行のみ大文字に置換
xargs                                         | # 行列変換
tr -d ' '                                       # 空白の除去

以下、コピペ実行用のワンライナーコード。

echo abcdefghijklmn | grep -o . | sed '2~2y/abcdefghijklmn/ABCDEFGHIJKLMN/' | xargs | tr -d ' '

問2

sed でFizzBuzzする問題。

この問題、Google検索すると、熟練のシェル芸人 @eban さんのずばりな記事が出てきたりする。
https://fizzbuzz.g.hatena.ne.jp/eban/20100313/1268475046
…​これ以上改良する余地が無い&& s コマンド縛りをしているので、代わりに c コマンドを使って、何とかオリジナリティを出してみる。

#!/bin/sh

seq 1 100                                             | # 1から100までの出力
sed '5~5cBuzz'                                        | # 5の倍数行をBuzzに置換
sed -e '3~3{/[0-9]/cFizz' -e '/Buzz/cFizzBuzz' -e '}'   # 3の倍数行かつ数値をFizzに、BuzzをFizzBuzzに置換

以下、コピペ実行用のワンライナーコード。

seq 1 100 | sed '5~5cBuzz' | sed -e '3~3{/[0-9]/cFizz' -e '/Buzz/cFizzBuzz' -e '}'

問3

3行目の内容を7行目の直後へ移動する問題。

ホールドスペースの練習のような問題。
3行目の内容をホールドスペースに入れる&&出力されないように削除して、7行目のパターンスペース処理時に追記するだけ。

#!/bin/sh

seq 1 10         | # 1から10までの出力
sed '3{h;d}; 7G'   # 3行目を7行目の直後に移動

以下、コピペ実行用のワンライナーコード。

seq 1 10 | sed '3{h;d}; 7G'

問4

C++ ソースコードにおいて、関数の記述位置を入れ替える問題。

ホールドスペースを活用する、発展的な問題。
正規表現によるアドレス指定を用いて、main関数部分のみをホールドスペースに入れる。
ここでのポイントは、 d コマンドの動作。
d コマンドには、パターンスペースの内容を削除するだけでなく、 以降のコマンドを実行せず、次のレコード処理を開始する という機能がある。
これを利用することで、 /}/G の処理をmain関数部分には実行させないようにしている。

#!bin/sh

cat aho.cc                   | # ソースコードの出力
sed '/main(/,/}/{H;d}; /}/G'   # main関数部分を、次の関数部分以降に移動

以下、コピペ実行用のワンライナーコード。

cat aho.cc | sed '/main(/,/}/{H;d}; /}/G'

問5

奇数・偶数行を入れ替える問題。

問2と3の応用的な問題。
奇数行をホールドスペースに入れる&&削除し、偶数行に追記してやればOK。
…​ただ、時間中に解答したコードは、 @eban さんの指摘で無駄な内容があることが判明した (´・ω・`)

問4で d コマンドの動作を利用していたのに、何で忘れていたんだ…​orz
という事で、この場で改めて解答をば。

#!/bin/sh

seq 1 10          | # 1から10までの出力
sed '1~2{h;d}; G'   # 奇数・偶数行の入れ替え

以下、コピペ実行用のワンライナーコード。

seq 1 10 | sed '1~2{h;d}; G'

問6

入力を階段状に増やしていく問題。

ここから一気に難易度がアップ。流石に s コマンド縛りはキツいので、ここから解禁をば…​
難しいけれど、普段のシェル芸と同様に、1つずつ処理を考えていけばOK。
p コマンドで入力を増殖してやった後、1行目以外の行に対して、ホールドスペースへ追記 → パターンスペースへ追記 → 改行を削除していく。
最後の sed については、ホールドスペースに追記した後、即座にパターンスペースに追記してやるのがポイント。

echo 1                              | # 1の出力
sed 'p; p; p; p; p; p; p; p; p'     | # 入力を10レコード分水増し(縦方向に増やす)
sed '1!{H; G; s/\n//g}'               # 1行目以外に対して、入力を横に増やしていく

動作を一つ一つ追っていくと、以下のようになる。

レコード  入力 パターン ホールド 出力 コマンド 解説
1行目     1                                    レコード処理開始
1行目     1    1                               入力をパターンスペースに取り込む
1行目          1                 1             パターンスペースの自動出力

2行目     1                                    レコード処理開始
2行目     1    1                               入力をパターンスペースに取り込む
2行目          1        1             H        パターンスペースをホールドスペースに追記
2行目          1\n1     1             G        ホールドスペースをパターンスペースに追記
2行目          11       1             s/\n//g  パターンスペースの改行を除去
2行目          11       1        11            パターンスペースの自動出力

3行目     1             1                      レコード処理開始
3行目     1    1        1                      入力をパターンスペースに取り込む
3行目          1        1\n1          H        パターンスペースをホールドスペースに追記
3行目          11\n1    1\n1          G        ホールドスペースをパターンスペースに追記
3行目          111      1\n1          s/\n//g  パターンスペースの改行を除去
3行目          111      1\n1     111           パターンスペースの自動出力

(以下略)

ただ、模範解答や他の方の解答を見ていたら、ラベルを用いた反復処理で解くのが、一般的な方法らしい。

以下、コピペ実行用のワンライナーコード。

echo 1 | sed 'p; p; p; p; p; p; p; p; p' | sed '1!{H; G; s/\n//g}'

問7

特定の縛りで、ファイルを連番コピーする問題。

縛りの内容は、以下の通り。
- 縛り1: 使うコマンドはseq、cp、sedだけ - 縛り2: ワンライナー中で数字を使わない

…​ただ、この縛り、実は片方だけで良かったらしいorz
まあ、せっかく縛り1・2を満たした解答が作れたので、結果オーライと言うことで!

seq inf              | # 1から延々と出力
sed '/../q'          | # 入力が2桁(10)になったレコードで打ち切り
sed 's/.*/cp a a&/e'   # コマンドの生成 && 実行

ちなみに、 @blacknon_ さんのツイートでふと気づいたのだけれど、 seqinf 指定子は、 man seqinfo seq にも書かれていない機能らしい。

かく言う僕も、ベテランシェル芸人の @Heliac1999さんに教えていただいて初めて知ったので、玄人しか知らない、正に隠し機能なのかもしれない…​

以下、コピペ実行用のワンライナーコード。

seq inf | sed '/../q' | sed 's/.*/cp a a&/e'

問8

入力を階段状に増やしていき、最後に鏡合わせに出力する問題。

問6の応用問題。
問6と同様に、入力を縦・横に増やした後、 sed スクリプトの例として頻繁に挙げられる、 tac と同等の動作 1!G;h;$p を少し弄ればOK。

上記スクリプトに関しては、 kunst1080さんのこちらの記事が詳しい。
http://www.kunst1080.net/entry/2014/12/16/234709

また、鏡合わせに出力する方法に関しては、手前味噌だけれど、こちらの記事で全く同じスクリプトを解説している。
http://qiita.com/gin_135/items/773fec1343a69c9f90d6

#!/bin/sh

echo 1                      | # 1の出力
sed 'p; p; p; p'            | # 入力を縦に増やす
sed '1!{H; G; s/\n//g}'     | # 入力を横に増やす
sed 'p; 1!G; $!h; $!d'        # 鏡合わせに出力

以下、コピペ実行用のワンライナーコード。

echo 1 | sed 'p; p; p; p' | sed '1!{H; G; s/\n//g}' | sed 'p; 1!G; $!h; $!d'

雑記

ここ最近、シェル芸各界で sed が緩やかなブームになっている気がします。
上田会長がイントロで触れられていたように、SDのシェル芸特集執筆にて、ベテランの方々が sed に興味を持つようになった事が影響しているのかな、と思いました。
また、昨年度自分が書いた記事が、思わぬ形で役に立つことになったり。
一見難解だけれど、地道に動作を追っていけば理解できる。また、スクリプトを少し変更するだけで、動作が大きく変わる点が、 sed の1つの魅力かな、とも感じました。
にしても、 sed こわい…​

また、以前ちょこっと話題にした、名古屋サテライト会場ですが…​
今月下旬から千葉県に引っ越すことになったので、名古屋サテライト会場の開設は難しい状況になってしまいましたorz
期待してくださった皆さんには、本当に申し訳ないです…​ 今年から名古屋城を借りられるそうなので、そこでシェル芸勉強会をやってみたかった…​…​
名古屋城本丸御殿、一般貸し出しへ:一面:中日新聞(CHUNICHI Web)


最後に、勉強会を開催してくださった、上田会長をはじめとした日本UNIXユーザ会とUSP友の会の皆様、いつも本当にありがとうございます!!

Tags: シェル芸 Unix
このエントリーをはてなブックマークに追加