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

シェル芸 ver.30 勉強会Report

第30回危念シェル芸 5周年おめでとうございます。久しぶり参加しました。 総じて楽しかったです。内容は午前の部と午後の部と2部構成でした。

atnd.org

午前の部

  • やりたい文字列と正規表現があって、その間を記号で繋げる
  • 正規表現自身に、SLASHが入るときは、Bracketを使うと見やすい
  • 変数展開でさまざまな文字列を指定文字列に変換できる* RubyPerlのを参考にして作られた言語
  • iをつけると、大文字小文字を区別しない
  • s/ / /s シングルラインモード
  • コンテキストの概念が重要(スカラーコンテキスト or リストコンテキスト)
  • ^もキャレットアンカー、$もドルアンカーっていう言い方をするらしい
  • クラシックなPerl文字class
  • クラシック文字クラスは大文字にすると否定
  • echo 1 2 3 4 5 | perl -pe ’s/\d+/sin($&)/eg' eg でperlとして実行できる
  • Unicode属性 InとIsがある
  • アンカー 単語境界
  • クロイスタ パターンを無効化
  • ルックアラウンドアサーション 先読みと後読みで達人の領域らしい

Perl正規表現第2回めでしたが、スライド進む度だんだん難易度が上がってる気がしてて 難しく感じたのもありましたが、スライドとターミナルと交互に実行結果などで 説明頂きました。Youtureに残していただいてるのであとから見直すことも出来ありがたかったです。

午後の部

  • 案件ネタ(html、ネットワーク)
  • パズル(脳みそに電極)

Q1

$ tree posts
posts
├── 20170806_check_of_webhook
│   └── main.md
├── 20170810_negi
│   ├── green_negi.jpg
│   ├── main.md
│   ├── white_negi.jpg
│   └── ねぎ.pdf
├── 20170810_negistagram
│   └── main.md
├── 20170812_work
├── 20170812_working
│   └── main.md
├── 20170814_layout
│   └── main.md
├── 20170818_bash
│   └── main.md
├── 20170820_bootstrap
│   └── main.md
├── 20170820_injection
│   └── main.md
└── template
    └── main.md
  • この中の、各main.mdは次のようなヘッダ付きのマークダウンです。
$ cat posts/20170818_bash/main.md 
---
Keywords: 嫌がらせ
Copyright: (C) 2017 Ryuichi Ueda
---
 
# 検索機能への嫌がらせ
Keywords: ワッショイ
Keywords: ワッショイ
Keywords: ワッショイ
  • これらのファイルから、次のような出力を作ってください。なお、Keywordsの行は各ファイルで最初にある行しか抽出しないこととします。
20170806_check_of_webhook Keywords: Webhook
20170810_negi Keywords: ネギ
20170810_negistagram Keywords: Twitter, Instagram, ネギ
20170812_working Keywords: 働けども働けども, bashcms2
20170814_layout Keywords: table, 雑
20170818_bash Keywords: 嫌がらせ
20170820_bootstrap Keywords: Bootstrap
20170820_injection Keywords: injection
template Keywords: 

$ ggrep -nr ‘Keyword’ ./ | ggrep ‘/main.md:2:’ | gsed ’s;./posts/;;‘ | gsed ’s;/main.md:2:; ;’

2行目がコメントだったので、grep -n オプションを使用 grep -m 1 で1行表示することもできるということを知った。grep 奥が深いなと感じました。

Q2

  • 次のHTMLファイルurl.htmlについて、リンクが相対パスになっているものについては頭に/files/をつけて、/から始まっているものとhttpやhttpsから始まっているものはそのままにしてください。できる人は変なところに改行があるものなどに対応できるように、なるべく一般解に近づけましょう。
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <ul>
    <li><a href="./hoge.html">ほげ</a></li>
    <li><img src="ayasii.jpg" alt="怪しい" /></li>
    <li><a href="https://blog.ueda.tech/">クソブログ</a><a href="huge.html">ふげ</a></li>
    <li><a href="/root.jpg"></a>これはそのまま</li>
    <li><a href="http://www.usptomo.com/">更新してない</a></li>
  </ul>
</body>
</html>

$ cat url.html | sed -r ’s;(img src=“|a href=”);&/files/;g' | sed -r ’s;(href=“|src=”)/files//;\1/;‘ | sed -r ’s;(href=“|src=”)/files/(https://|http://);\1\2;g’ | sed ’s;/./;/;g'

sed で頑張って変える感じでした。sed -r のバックスラッシュが省略がしらなかった sedの使い方がスマートでした。

Q3

次のファイルについて、

$ cat list
* 妬み
* 嫉み
* 僻み

次のようにHTMLにして、頭にHTTPヘッダをつけてください。インデントは不要ですがタグは1行1個でお願いします。

Content-Type: text/html
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
<ul>
<li>妬み</li>
<li>嫉み</li>
<li>僻み</li>
</ul>
</body>
</html>

すぐできて退屈な人は、インターネット上のサーバでこのHTMLファイルを送信するサーバをワンライナーで立ててください。

$ pandoc list -t html5 -s | sed ‘5,12d’ | sed ‘1iContent-Type: text/html\n’

知らなかった、「pandoc」コマンド。めちゃくちゃいい。 今までhtml5はテンプレートを予めsnippetとかで作ってたので、今後はそんな手間もなくなりそう。 その他にも色んな種類があるので、使い分けていきたい。

htmlファイルを送信するサーバをワンライナーで立てるということで、nc コマンドを教わった。 オプションが充実しててスゴイ役立ちそうな印象。

Q4

&&や;でコマンドを繋いだワンライナーで、GitHubリポジトリを作ってそこにテキストファイルを一つ置いてください。

mkdir hoge && cd hoge && git init && echo aho > aho.txt && git add -A && git commit -m “aho” && hub create ryuichiueda/hoge && git push origin master

&& でワンライナーで別々のコマンド叩けるんだなぁという印象。hubコマンド便利

Q5

次のファイルの1行目の複素数と2行目の複素数をかけ算してください。

$ cat complex 
1 + 4*i
3 - 2*i

$ cat complex | sed ’s/^/(/‘ | sed ’s/$/)/’ | sed ‘2,$i*’ | xargs | tr -d ‘ ’ | xargs -I@ perl -e ‘{use Math::Complex;print(@);print “\n”}’ 11+10i

TwitterのTLでは、いろんなのをくぐらせて答えを出していて、用途は様々だなと見てて楽しかったです。

cat complex | awk ‘BEGIN{FS=“ ”}/1/{a=$1;b=$2 $3};/2/{c=$1;d=$2 $3};END{r=ac-bd;i=ad+bc;print r (i<0?“-”:“+”) i “i” }’

Q6

フィボナッチ数列で、6765の4つ前の数を出力してください。

$ echo a | awk ‘BEGIN{a=1;b=1}{while(1){print a;c=b;b+=a;a=c}}’ | grep -m 1 -B4 6765 | head -n 1 987

Q7

次の数字の列について、00, 01, 02,…,99の数字2つ並びのうち、含まれないものを抽出してください。できる人はループを使わないで抽出してください。

$ seq -w 0 99 | while read n ; do grep -q $n nums || echo $n ; done

Q8

次のアルファベットの区間のうち、間に含まれるアルファベットが一番多いものはどれでしょうか。出力は何行目に書いてある区間かを数字で出せば良いこととします。

$ cat alphabet 
a-g
e-q
z-v
r-y

$ cat alphabet | awk ‘{a=$1;gsub(/-/,“..”,a);print “echo”,$1,“{"a”}“}’ | bash | awk ‘{print $1,NF}’ | sort -k2,2n | tail -n 1 | awk ‘{print $1}’

午後の部おわって

福岡では、コマンドを使ってて出た疑問について質問しました。

コマンドの文字列長に制限があるから、大量のファイルを処理するときにどう扱えばいいのか?

OSのヘッダーファイルにかかれていて、設定がある

問題点

  • 処理できる長さ制限

解決策

  • xargs を使うと、kernelができるところまでやって、オーバーしそうになったら次に行くように進める

xargs で問題なるところ

  • 時刻別で並び替えたいときの問題

xargs のオプションでなれておくこと

  • -I@ で指定の場所に標準入力の出力結果を@ でおくことができる

  • -P background処理

  • -n 1 ひとつずつ実行(コマンドによって、単一ファイル前提)

以下のテクニックは知っておいてすごく便利だなと使って思ったので、使いこなしたいなと思いました。また機会があれば参加したいです。 ありがとうございました。

pandoc
cat - <(seq 1 10)
nc 

コマンドラインで作成したファイルを実行する

※Laravel 5.3 で検証しております。バージョンによって書き方が異なる場合がありますので、確認が必要がと思われます。

 

$ php artisan --version
Laravel Framework version 5.3.31

 

ターミナルで、まとまった処理を実行するときにコマンドがあると便利ですね。

 

作成するのにartisan コマンドを使用します。

 

php artisan だけで実行すると、コマンドの説明が表示されます。

 

make に関するコマンドはこれだけあります。 

 

 

make:auth Scaffold basic login and registration views and routes
make:bindings Add repository bindings to service provider.
make:command Create a new Artisan command
make:controller Create a new controller class
make:criteria Create a new criteria.
make:entity Create a new entity.
make:event Create a new event class
make:job Create a new job class
make:listener Create a new event listener class
make:mail Create a new email class
make:middleware Create a new middleware class
make:migration Create a new migration file
make:model Create a new Eloquent model class
make:notification Create a new notification class
make:policy Create a new policy class
make:presenter Create a new presenter.
make:provider Create a new service provider class
make:repository Create a new repository.
make:request Create a new form request class
make:resource Create a new RESTfull controller.
make:seeder Create a new seeder class
make:test Create a new test class
make:transformer Create a new transformer.
make:validator Create a new validator.

 

 

 

 php make:command で作成します。

 

 

作成後、Kernel.phpに登録します。

 

laravel/app/Console/Kernel.php

 

/**
* アプリケーションで提供するArtisanコマンド
*
* @var array
*/
protected $commands = [
Commands\ClassName::class,
];

 

 

laravel/app/Console/Commands/ClassName.php

 

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'classname:register';

 

好きな名前をつけて下さい。

 

修正したら、コマンド実行

 

php artisan classname:register 

 

修正がうまくいくと、php artisan で一覧に表示されます。

 

 

 

 

 

 

 

 

 

 

 

 

jsonbの部分更新

jsonスキーマはpostgreSQL9.2 から取り扱えるようになり多様なデータ構造を持つことが出来るようになりました。key value のセットでデータ保存しますが

 

# select version();
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 9.6.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-17), 64-bit
(1 row)

 

データの部分更新をしたいときですが、value がstring かnumber で更新方法が違いました。例えばこうゆうデータがあって

 

# select id, json_contents from notifications limit 1;
-[ RECORD 1 ]-+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | 1
json_contents | {"offer_id": 4333}

-[ RECORD 2 ]-+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | 2
json_contents | {"offer_id": "4333"}

 

number と string で定義されたoffer_id があります。この場合だと

select * from notifications where json_contents = jsonb_set(json_contents, '{"offer_id"}', '4333');

で、1件しかとれません。(id:1 のほう)

なので、整合性のため、データを揃えます。

update
  notifications
set
 json_contents = '{}'::jsonb || json_contents || json_build_object('offer_id',(json_contents->>'offer_id')::integer)::jsonb
;

update table_name set col = default || 'hohfeofe' の発想です。

一旦空のデータを作ってから、元コンテンツをmergeして、offer_id に対して、元データをstring -> integer -> jsonb にキャストしてます。

 

この場合だと、jsonのvalue string -> integer , integer -> string でもいけると思います。

 

 

 

広告を非表示にする

特定のフォルダ以下でのディスク容量

そもそもの始まりは

 という自分のTweet。 

どうも実行結果が計算合わない。。

 

 

現在のサーバを、どの程度ディスク容量使っているのかを調べるのに自分はよく

$ df -h

を使います。

このdf コマンドは実バイトを返さないということを知ったので詳細なデータを知りたい場合、例えば画像フォルダが何十万とあるフォルダ以下のバイト数を調べるにはどうしたらいいのか。

 

1. find DIR -type f | wc -c

自分が最初に行ったパターンです。明らかに違いました。この場合だと、参照先のファイル名の長さの総和に確かになってました。。

 

2. find DIR -type f | xargs ls -l | awk '{sum+=$5}END{print sum}'

このパターンは、Twitterで教えていただきました。この場合うまくいきました。この場合だと、ls -l で隠しファイルを含めないので純粋に画像のバイト数の総和を出すことが出来ました。

 

3. find DIR -type f | xargs wc -c | grep total | awk '{sum+=$1}END{print sum}'

wc -c でバイト数を計算する方法です。ただ、grep total | awk '{sum+=$1}END{print sum}' をつけないとwc -c | tail -n 1 の場合だと、うまくいかなかったのですがこちらに関しても教えてくださいました。

 

 

4. du -sh DIR

こちらの場合ですと、隠しフォルダのバイト数も含まって純粋な画像データとしては出せませんがシンプルという意味では使えるかなと思いました。

 

 

 

コマンドを扱う場合にオーバーフローが起こる可能性や、コマンド最大長があるということも知っていい勉強になりました。

 

 

Acrobat Pro DC をつかってPDFファイルの表をexcelに出力

PDFの表になってる部分をexcelにしたく、

ネットでググってもどうしても貼り付けられない。。

試行錯誤の末にとりあえず、それっぽいのが出力できました。

 

  1. 該当のPDFファイルを「Acrobat Pro DC」を使って開く
  2. 文章構造を読み込ませる
  3. PDFを書き出し
  4. スプレットシート Microsoft Excel ブックの設定をクリック(歯車のマーク)
  5. テーブルごとにワークシート作成
  6. 書き出し
  7. 書き出されたファイルを開く

 

あとは、指定のシート開いて加工すればいいかと思います。

ただ、どうしてもセル結合してたりとかあったりするんで、そこは対応してあげないといけないみたいです。

QueryBuilder::paginate() と Eloquent::paginate() の挙動の違いがあった

 

Laravel ver: 5.3.26

 

SQL的にcount() で取得するときには、主にそのテーブルの主キーをあてるほうがより速く実行することが出来ます。

 

今回、QueryBuilder::paginate() と Eloquent::paginate() の挙動の違いがあったためメモします。

データを取得するとき、第二引数に$column (default =['*']) を指定することが出来ます。

 

今回、DBオブジェクトが持ってるQueryBuilder::paginate()の場合だと、

/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);

$total = $this->getCountForPagination($columns);

$results = $total ? $this->forPage($page, $perPage)->get($columns) : collect();

return new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}

 

 

    $total = $this->getCountForPagination($columns);
}

 

で、countを取得しています。

 

一方、Modelオブジェクトが持っているEloquent::paginate()だと、

 

/**
* Paginate the given query.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*
* @throws \InvalidArgumentException
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);

$perPage = $perPage ?: $this->model->getPerPage();

$query = $this->toBase();

$total = $query->getCountForPagination();

$results = $total
? $this->forPage($page, $perPage)->get($columns)
: $this->model->newCollection();

return new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}

 

    $total = $query->getCountForPagination();

 

と、$column名が引数に渡ってないため、呼ぶ側が明示してもcount(*) と実行されるみたいです。

 

以上、使ってみて気づいたことでした。

 

本体に報告してみたいのですがやり方はまた調べて、fixしてもらえるようにしたいと思います。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

baserCMSを使ってサイト公開した話

baserCMS Advent Calendar 2016 - Adventar 3日目を担当させていただきました。よろしくお願いします。

http:// http://www.adventar.org/calendars/1703

 

 

昼食にいつも使っている定食屋さんがあって、

日頃良くしていただいているので、サイトを作りましょうと話が上がったため

今年のお盆前にbaserCMSを使って公開しました。

kitchen-yumeya.com

 

baserCMSは当時(baserCMS 3.0.10)でのインストールでした。

パッケージは公式サイトからダウンロードします。

 

インストールは、以下のような作業を行いました。

  1. zipファイルを右クリックでダウンロード
  2. ダウンロードしたzipファイルを解凍
  3. 解凍したフォルダをサーバにアップロード
  4. インストールページを表示
  5. インストールページのガイダンスに従って、フォルダのパーミッション修正
  6. データベースの指定(今回、PostgreSQLにしました。)
  7. サイト上で使うテーマ選択
  8. インストール完了

 

インストール完了すると、指定したテーマが公開されます。

 

しかし、今回別のテーマにしたかったため、探してみたところ、「baserマーケット」というのがありました。

market.basercms.net

 

baserCMSでカスタマイズを行うのに便利なプラグインやテーマを販売しているサイトのようです。

プラグイン、テーマを購入するのには会員登録が必要なため、baserCMSインストール作業で使用したメールアドレスを使って会員登録しました。

 

会員登録後、早速テーマを探してみました。

用途別に様々なテーマを選択できるみたいです。

f:id:kashii1207:20161203100820p:plain

 

今回「飲食店」なので、こちらのテーマを使用させていただきました。

f:id:kashii1207:20161203101036p:plain

baserCMSで公開されてあるテーマはどれもクオリティが高くテーマごとにどうゆうところを意識して作ったかなどの「商品説明」が記載がしっかりされているため、選ぶ側としても納得して選ぶことができます。

しかも、無料配布されているものも数多くあるためbaserCMSを使用しているユーザにとってはとてもありがたいです。

 

テーマを決めたので、「カートに入れる」を押して購入手続きを進めます。

 

購入手続きの流れは以下の通りでした。

  1. 現在のカゴの中(カートの中身を確認)
  2. 支払い方法・お問い合わせ入力
  3. 入力内容確認
  4. 注文完了

簡単ですね。

「baserマーケット」はダウンロードコンテンツを販売するサイトなのでお届け先の入力は必要ありません。

 

購入完了後、早速適応してみました。

f:id:kashii1207:20161203102831p:plain

 

TOPのメインビジュアルは、管理画面から差し替える事が可能ですので、

お店の看板メニューがどどんと出るように差し替えました。

f:id:kashii1207:20161203103340p:plain

 

デフォルトで使われている画像や文言を差し替えたいときには、「固定ページ管理」で編集することが出来るみたいです。ここでは、各ページで使われている画像の差し替えなどを行いました。

 

余談ですが、固定ページでは管理しない部分は、テーマ一覧から編集することも可能です。

f:id:kashii1207:20161203103811p:plain

 

「レイアウトテンプレート 一覧」ページが表示されますが、主に以下のような用途ごとにメニューがわけられているようです。どうやら、Webサイトの構成に従って共通化している部分をまとめて管理しているみたいですね。

  1. レイアウト一覧(layout)
  2. エレメント一覧(Elements)
  3. Eメール一覧(Email)
  4. コンテンツ一覧(content)
  5. css一覧(css
  6. イメージ一覧(img)
  7. Javascript一覧(js)

※作業する際には、元に戻せなくなって動かなくなったとか怖いんで編集前に「複製」してバックアップしておくことをおすすめします。

 

 

サイトを公開したら、解析タグを入れたりするのに、GoogleAnalyticsなどで設定しておくといいですね。

www.google.com

 

できあがったGoogleAnalyticsのタグには、「UA-」から始まる文字列が作成されますので、baserCMSの管理画面の「システム管理」から設定してください。

 

 あとは、Googleエゴサーチしたときに紹介できるように設定しておくのもいいですね。

地図上に住所が表示されたりしますが、そこに「営業時間」「Webサイト」などの情報を入れたりすると、今日のランチどうしようかなって思う人に対して集客もできるので設定しておくのも効果はあると思います。

f:id:kashii1207:20161203114423p:plain

 

今回、お店の人に内緒でサプライズでやってみましたが、お店の人から「Google」から検索で☆がついてたからお客様が来たとか、中には地方アイドルがレポートさせてくださいとご来店があったとか嬉しい報告をたくさんしていただけましたし、なによりサイト作って大変喜ばれたのがうれしかったですね。

 

CMSでサイト構築をご検討の方は参考にしていただけるとありがたいですね。

以上です。