第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 さんの指摘で無駄な内容があることが判明した (´・ω・`)
@gin_135
— eban (@eban) 2017年2月11日
ああ、dでつぎのサイクルに移行するので2~2は不要ですね
% seq 1 10 | sed '1~2{h;d};G'
2
1
4
3
6
5
8
7
10
9#シェル芸
問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_ さんのツイートでふと気づいたのだけれど、 seq
の inf
指定子は、 man seq
や info seq
にも書かれていない機能らしい。
seqのinfってなんだ…?#シェル芸
— Blacknon(エビス) (@blacknon_) 2017年2月11日
@gin_135
— Blacknon(エビス) (@blacknon_) 2017年2月11日
そんな機能が…知らなかった
回答見てからググったのですが、出てこなかったです
かく言う僕も、ベテランシェル芸人の @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'
参照Webサイト
jus共催 第9回初心者満足度ナンバーワン(当社調べ・調べてないけど)シェル勉強会/第27回sedこわいシェル芸勉強会
→ 勉強会の概要。シェル芸 のライブ ストリーム
→ 今回の勉強会の動画配信(アーカイブ)。第27回sedこわいシェル芸勉強会- Togetterまとめ
→ 参加者の当日の様子。
雑記
ここ最近、シェル芸各界で sed
が緩やかなブームになっている気がします。
上田会長がイントロで触れられていたように、SDのシェル芸特集執筆にて、ベテランの方々が sed
に興味を持つようになった事が影響しているのかな、と思いました。
また、昨年度自分が書いた記事が、思わぬ形で役に立つことになったり。
一見難解だけれど、地道に動作を追っていけば理解できる。また、スクリプトを少し変更するだけで、動作が大きく変わる点が、 sed
の1つの魅力かな、とも感じました。
にしても、 sed
こわい…
また、以前ちょこっと話題にした、名古屋サテライト会場ですが…
今月下旬から千葉県に引っ越すことになったので、名古屋サテライト会場の開設は難しい状況になってしまいましたorz
期待してくださった皆さんには、本当に申し訳ないです… 今年から名古屋城を借りられるそうなので、そこでシェル芸勉強会をやってみたかった……
名古屋城本丸御殿、一般貸し出しへ:一面:中日新聞(CHUNICHI Web)
いつか名古屋城でシェル芸勉強会をして欲しい。なんか、借りれるらしいし。 #シェル芸
— Anubis (@Anubis_369) 2017年2月10日
最後に、勉強会を開催してくださった、上田会長をはじめとした日本UNIXユーザ会とUSP友の会の皆様、いつも本当にありがとうございます!!