日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です

「第31回シェル芸勉強会:福岡サテライト」レポート

前回に引き続き鬼の忙しさが続いていたが、忙しさに切れ目・・・しかし本当に若干の切れ目・・・なんとかシェル芸勉強会の福岡サテライトを開催することができた。今回も参加いただきありがたや。会場は今回もAIP Cafe。

午前中は会社の会議の後、昼からはシェル芸地獄というなかなかハードな一日だった。10月になったけど昼は暑いよ。今回は総勢4人の参加者が集った。久しぶりの参加の方もいらっしゃった。

勉強会募集サイト

本家東京会場募集

usptomo.doorkeeper.jp

大阪サテライト会場募集

atnd.org

福岡サテライト会場募集

atnd.org

イベント報告関連

今回のTLはどうだったのかな?

(上田会長による)jus共催 第30回危念シェル芸勉強会の報告

jus共催 第31回朝からだと疲れるから午後からでええじゃろシェル芸勉強会の報告 | 上田ブログ

(上田会長による)Togetterまとめ

togetter.com

午後の部

ということで今回は午後の部のみ。今回もイントロのスライドとか準備出来ず。せっかくなので持ってきたSoftware Design 9月号と10月号の宣伝をしたくらいだ。

今回の問題と解答は、下記の上田さんブログを参照のこと。上田さんのブログがついにbashCMSへと移植されたようだ・・・ざわ・・・ざわ・・・

jus共催 第31回朝からだと疲れるから午後からでええじゃろシェル芸勉強会の報告 | 上田ブログ

問題が難しい場合は関連情報の解説や補足を重視して、今回も福岡サテライトなりのペースで進めていくぞい。

Q1

行をまたいだ置換の問題。工夫すればsedで出来そうだがわからん・・・解答例を後から見ることにして、福岡では補足や解説が重要なのでsedの後方参照やyコマンド、拡張正規表現などの説明をした。後方参照出来る数は9個までだよとか。

# こんな感じで\( \)で囲った部分を\1\2で順番に参照出来るよ
$ echo 123-45 | sed 's/^\(...\)-\(..\)/\1\2/'
12345

# GNU sedの-rオプションで拡張正規表現が使える。参照したい部分の囲みにバックスラッシュが不要。
$ echo 123-45 | gsed -r 's/^(...)-(..)/\1\2/'
12345

# yコマンドで変換だぞ
$ echo 12345 | sed 'y/12345/abcde/'
abcde
$ echo 12345 | sed 's/12345/a/'
a

# trコマンドでも出来る。sedより高速だが動きが違う部分も。
$ echo 12345 | tr '12345' 'abcde'
abcde
$ echo 12345 | tr 12345 a
aaaaa

解答例ではPerl正規表現のルックアラウンドアサーションを使うということだった・・・復習せにゃ。Perlの正規表現はPCREとしてライブラリで提供されており、PHPやApache HTTP Serverなどでも利用可能だよとか補足解説。

PCRE - Perl Compatible Regular Expressions

Q2

上の行に合わせたインデントをする。Vimのインデントコマンド=で出来ないか?と思ったが、わての実力では出来なかった・・・

Vimでやっている人がいた。

ちなみにJavaScriopt(node)で解いている人もいて、もう意味がわからない。

Q3

問題の図形を見て素数がすぐに出てくるのは変態。シェル芸界隈では定番になってきているが福岡サテライトではまだ十分知られていないので、素数列挙の定番ワンライナーを解説。

$ seq 1 20 | gfactor | awk 'NF==2{print $2}'
2
3
5
7
11
13
17
19

後はawkで頑張ればなんとかなりそう。ということで最終的には会長の解答に。

Q4

福岡サテライトの参加者は、ASCIIコードやバイナリデータの扱いに慣れていない方が多かったので補足解説。

# まずはマニュアルを見て見る
$ man ascii

# odコマンドでASCIIコードを16進数表記
$ echo -n ABCabc | od -t x1c
0000000    41  42  43  61  62  63                                        
           A   B   C   a   b   c                                        
0000006

# BSD版だとマルチバイトに対応してるよ。
$ echo -n おはようございます | od -t x1c
0000000    e3  81  8a  e3  81  af  e3  82  88  e3  81  86  e3  81  94  e3
          お  **  **  は  **  **  よ  **  **  う  **  **  ご  **  **  ざ
0000020    81  96  e3  81  84  e3  81  be  e3  81  99                    
          **  **  い  **  **  ま  **  **  す  **  **                    
0000033

# vim付属のxxdコマンドで16進数表記。
$ echo -n おはようございます | xxd
00000000: e381 8ae3 81af e382 88e3 8186 e381 94e3  ................
00000010: 8196 e381 84e3 81be e381 99              ...........

# -uオプションで10進数表記
$ echo -n おはようございます | od -t u1c
0000000   227 129 138 227 129 175 227 130 136 227 129 134 227 129 148 227
          お  **  **  は  **  **  よ  **  **  う  **  **  ご  **  **  ざ
0000020   129 150 227 129 132 227 129 190 227 129 153                    
          **  **  い  **  **  ま  **  **  す  **  **                    
0000033

# -bオプションで2進数表記。ビット列が見えるよ。
$ echo おはようございます | xxd -b
00000000: 11100011 10000001 10001010 11100011 10000001 10101111  ......
00000006: 11100011 10000010 10001000 11100011 10000001 10000110  ......
0000000c: 11100011 10000001 10010100 11100011 10000001 10010110  ......
00000012: 11100011 10000001 10000100 11100011 10000001 10111110  ......
00000018: 11100011 10000001 10011001 00001010                    ....

Q5

Q4でのASCIIコードやバイナリデータに解説してたら、あまり時間が無くなる。解答例に出てきたプロセス置換について解説をした。

# 2つのコマンドの出力結果をdiffで比較
1d0
< 1
3a3
> 4

シェルの本質はコマンドの実行とプロセス管理、ファイルをベースとしたデータ入出力の管理、といったことを解説。補足として/dev/urandom/procファイル、bashのtcp通信機能など、ファイルをベースとした機能も。

# 乱数取得のワンライナー。trの-dcオプションについても補足解説。
$ cat /dev/urandom | LANG=C tr -dc '0-9' | fold -w 10 | head
5185330642
4941724968
8040182629
4953975155
7776003351
2268161449
3516241602
2661394339
7045619931
7999489264

Q6

UTF-8な日本語ひらがなを小文字に変換する問題。参加者から文字コードをズラせばいいんじゃない?という意見が出る。じゃあ確認してみよう。

$ echo -n あぁ | xxd -p | fold -w 6
e38182
e38181

ということで、3バイト毎にまとめてコード番号を1引けば良さそう。ということで考えた解答例がこちら。やっと1問だけちゃんとした解答が出せた・・

$ echo -n あいうえお | xxd -p -u | fold -w 6 | sed 's/$/ - 1/' | (echo 'obase=10;ibase=16'; cat) | bc | (echo 'obase=16'; cat) | bc | xxd -p -r
ぁぃぅぇぉ

bcコマンドについては知られていなかったので補足解説。bashbc自体の履歴機能が使えるので、繰り返し計算する時の電卓替わりにも便利だよ。

Q7

アニメーションを作る問題。解答を作るのは断念。

そもそも端末でアニメーションを作るにはどうすればいいか?という解説をした。例えば1秒毎に@が一つずつ伸びていくにはこんな感じとか。

# まずはコマンド列を作成する
$ seq 3 | awk '{for(i=1;i<$1;i++){printf "@"}print ""}' | sed 's/^/clear; echo /' | sed 's/$/; sleep 1;/'
clear; echo ; sleep 1;
clear; echo @; sleep 1;
clear; echo @@; sleep 1;

# 上記のコマンドをシェルに流し込んで実行。
$ seq 3 | awk '{for(i=1;i<$1;i++){printf "@"}print ""}' | sed 's/^/clear; echo /' | sed 's/$/; sleep 1;/' | sh

Q8

全角5文字以内で折り返す問題。ギブアップ・・・

Q9

スクレイピングの問題。CSVにするのは諦め元素記号だけを抽出するものを作った・・・敗北感。

$ curl -s http://www.gadgety.net/shin/trivia/ptable/ | sed -n '/<tr /,/<\/tr>/p' | grep font | grep '<a href="' | grep -o '<a href="[^"][^"]*\.html">[^<>][^<>]*</a>' |  sed 's/<[^<>]*>//g'
H
He
Li
Be
(省略)
Fm
Md
No
Lr

午後の部終了後

スライドの準備は出来なかったが、参加者の方でTwitterでxargsコマンドの使い方を色々悩んでた方がいらっしゃったのもあり、改めてxargsコマンドについて基本からおさえる話をした。

xargsについて

配列的なデータを扱う

  • 配列的な文字列データに対して、コマンド処理をまとめて実行する時に使う
  • 区切り文字はスペース、タブ、改行、EOF

使い方の基本例

$ find dir -type f | xargs file

$ echo {1..5} | xargs printf '%05d\n'
00001
00002
00003
00004
00005

コマンドを指定しない場合は、暗黙的にechoが実行される。

$ seq 10 | xargs -n 2
1 2
3 4
5 6
7 8
9 10

どんな処理をするコマンドか?

xargsはHaskellやRuby、JavaScriptのmapに似ており、配列的なデータに対して繰り返し同じ処理を施す。配列内の数字を2倍にする処理を考える。

# xargsコマンド
$ seq 1 5 | xargs -I@ expr @ \* 2
2
4
6
8
10

# Ruby
$ pry
[1] pry(main)> [1,2,3,4,5].map do |i| i*2 end
=> [2, 4, 6, 8, 10]

# JavaScript
$ node
> [1,2,3,4,5].map((n)=>{return n*2})
[ 2, 4, 6, 8, 10 ]

# PHP
$ php -a
php > print_r(array_map(function($num){return $num*2;},[1,2,3,4,5]));
Array
(
    [0] => 2
    [1] => 4
    [2] => 6
    [3] => 8
    [4] => 10
)

オプション

  • -nオプション
    一度に処理する数を指定

  • -Iオプション
    通常はコマンド列の最後に渡すが、埋め込む文字列を指定して自由にコマンド列を作成可能。

$ seq 5 | xargs -I@ gdate -d '@ day' +%F
2017-10-08
2017-10-09
2017-10-10
2017-10-11
2017-10-12
  • -0オプション
    ディレクトリ名やファイル名に空白などがある場合に便利。
$ find 'VirtualBox VMs' -print0 | xargs -0 file

複数のコマンドを実行するには?

複数のコマンドやパイプなどは実行出来ないが、shbash-cオプションを使うことでカバー可能。1秒毎に1カウントアップするワンライナーがこちら。

$ seq 10 | xargs -I@ sh -c 'echo @; sleep 1;'
1
2
(省略)
9
10
  • -Pオプション
    並列処理が可能。「真・マイナンバーシェル芸」の記事を紹介。

あとはImageMagickとの実用的な組み合わせで、画像ファイルを再帰的に選択してフォーマットの変換やサムネイル作成の処理をするワンライナーを紹介したり。

# PNG=>JPGへフォーマット変換
$ find * -type f -name '*.png' | sed 's/\.png//' | xargs -I@ convert @.png @.jpg

# 長辺が100x100ピクセル以内のサムネイル画像を作成。ファイル名に-sを追加。
$ find * -type f -name '*.png' | sed 's/\.png//' | xargs -I@ convert -geometry 100x100 @.png @-s.png

他にはcurlコマンドでデカイデータをPOSTする際にコマンドライン長制限の問題が出て困った、という話題が上がった。これについてはデータをファイルから読んで出来るのでは?と予測。

curlのマニュアルを見るとファイル名に@を付けて指定すれば良さそう。ググって調べて見るとファイル名に@を付ける方法で良さそうだ。

今回も疲れた!参加者の方々お疲れ様!!