第37回シェル芸勉強会メモ
https://b.ueda.tech/?post=20180901_shellgei_37 にて学んだことメモ。
Q1
FizzBuzzのアニメーション
seq 100 | gsed '0~3s/.*/Fizz/;0~5s/.*/Buzz/;0~15s/.*/FizzBuzz/' | # 0~3s みたいな書き方で3行ごとに置換を行う gawk '{printf("%08s\n", $1)}' | # 8桁で右揃えにする while read line; do clear; echo $line; sleep 0.5; done # でもこれだと右揃え表示されない...
Q2
echo ' /\' | sed ':a p;s@ /@/ @;b a' | head -n 4 | sed '$a ̄ ̄ ̄ ̄' | sed '3s;/ ;/ 👁 ;'
sedで何やっているのかわからないので、プロに教えていただいた。
# aコマンドで指定行のあとに文字列を差し込める。 # $a だと最終行に差し込む echo "hoge" | gsed '1a\fuga' hoge fuga # sの後につけた文字がデリミタになる # @を使った例 echo '//' | gsed 's@/@pp/@' pp// # sedで無限ループ # :aはラベル pは出力 # s@hoge@hogehoge@ で 置換(デリミタを@にしている) # bはラベルジャンプの意味。なので、b a でaラベルへジャンプ echo "hoge" | gsed ':a p;s@hoge@hogehoge@;b a' | head -n 5 hoge hogehoge hogehogehoge hogehogehogehoge hogehogehogehogehoge # 3sとやると3行目だけ置換する echo "hoge" | gsed ':a p;s@hoge@hogehoge@;b a' | head -n 5 | gsed "3s/hoge/fuga/g" hoge hogehoge fugafugafuga hogehogehogehoge hogehogehogehogehoge
Q3
3桁の中に同じ数がなく、各桁を足すと15になる数字。ゼロは含まない。
これは簡単。
seq -w 999 | grep -v "0" | gawk -v FS="" '($1!=$2 && $2!=$3 && $1 + $2 + $3 == 15){print $1$2$3}'
補足
seq -w 999 # これでゼロパディングできる gawk -v FS="" {} # これで1文字ごとに区切れる。
ActiveRecordのafter_commitが発火するとき発火しないとき
発火する
・なにも変更せずにsaveしても発火する(select文しかないtransactionでcommitがされるため)
・destroyで発火する。self.destroyed?はtrue, self.reloadでActiveRecord::RecordNotFound
・soft_destroyでも発火する。self.soft_destroyed?はtrue (kakurenbo-puti使用時)
・他のafter_commitがこけても発火する。
発火しない
・update_columnでは発火しない(トランザクションはっていないからcommitもない)
・validationエラー時はひっかからない(commitじゃなくてrollbackするので)
・DBエラー(unique制限)でrollbackしたときは発火しない(commitじゃなくてrollbackするので)
Homebrewのコマンドメモ
ちゃんとわかっていない感あったのでメモ。
## インストールされたformulaの一覧 brew list ## アンインストール brew uninstall FORMULA_NAME ## 更新のあるformulaを見る brew outdated ## 古いバージョンのformulaを削除 brew cleanup brew cleanup -n # 何が消されるのか一覧を表示する。 ## brew本体のアップデート brew update ## formulaのアップデート brew upgrade FORMULA_NAME ## formulaの情報見る brew info FORMULA_NAME ## tap(追加)したリポジトリの一覧 brew tap ## tapする/外す brew tap ユーザー名/リポジトリ名 brew untap ユーザー名/リポジトリ名 # このリポジトリでインストールしたformulaは先に削除しておく
第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会メモ
https://b.ueda.tech/?post=shellgei_38 より学んだことメモ
xxd コマンド
対象を16進数でダンプする/16進数から復元する。
pオプションはpostscript形式でダンプするの意味。
# ダンプする echo "ほげほげ" | xxd -p # 復元する echo "ほげほげ" | xxd -p | xxd -r -p # もやもやの文字コード echo d288 | xxd -r -p echo d289 | xxd -r -p
grep -f オプション
検索条件を保存したファイルでフィルターする
cat cond.txt あ い echo "あいうえお" | grep -o . | grep -f cond.txt あ い # リダイレクションと組み合わせる cat cond.txt あいうえお echo "あいうえお" | grep -o . | grep -f <(grep -o . cond.txt) あ い
sort -kオプション
# 2項目目以降でソート cat sample.txt | sort -k 2 # 2項目目だけでソート cat sample.txt | sort -k 2,2 # 1項目目だけを数値としてソート cat sample.txt | sort -k 1,1n
uniqで重複を抽出する
重複行の抽出する
# dオプションで重複のみ抽出 # fオプションで重複チェック除外フィールドを指定 (1を指定した場合は2以降で重複チェック) cat sample.txt | sort -k 2,2 | uniq -d -f 1
trコマンド
# 置き換え(文字数は揃える必要がある) echo 012 | gtr 012 abc # 大文字小文字変換 echo ABC | gtr A-Z a-z # 改行コードに変換 echo "A B C" | gtr ' ' \\n # 指定文字以外を削除する echo "1234567890abcdef" | gtr -dc 1234567890
nlコマンド
行数を表示
echo "A B C" | tr ' ' \\n | nl
foldコマンド
指定した幅で改行する
echo "ABCDEFGHIJK" | gfold -b5
ガウス分布な乱数生成
※0-1間の一様乱数を12回足して6引いた値の集合は、標準偏差1のガウス分布に従う。
※http://www.geocities.jp/jun930/etc/varianceofrandom.html
https://bellcurve.jp/statistics/blog/17953.html
cat /dev/urandom | gtr -dc 0-9 | gfold -b10 | gsed 's/^/0./' | gawk '{a+=$1}NR%12==0{print (a-6);a=0}'
指定範囲の文字を全部出力
echo {A..Z} A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
カンマのところで改行を入れる
cat sample.txt | gsed -e "s/,/,\\n/g"
nkf(NetworkKanjiFilter)
文字コード/改行コードの変換を行うコマンド
# -w UTF8に変換 # -Lu LFに変換 # -x 半角カタカナを半角のまま cat myoho_shinji.txt | nkf -wLux
xargsで、引数の数を指定する
cat hogefuga.txt hoge fuga cat hogefuga.txt | xargs -n 2 hoge fuga
awkの中で、コマンドの実行結果を得る
# コマンド | getline 変数 で、 # 変数にコマンドの実行結果が入る cat data.txt | gawk '{"hostname" | getline x; print x;}' suzukake.local suzukake.local suzukake.local suzukake.local
awkでバッファを出力する
fflush();
factorコマンドで素因数分解する
gfactor 12 12: 2 2 3
Q7分解
a^2 + b^2がab + 1で割り切れる正の整数の組合せa,bを生成してください(ランダムで良いです)。また、このとき、(a^2+b^2)/(ab+1)が正の整数の二乗になっていることを確かめてください。
awkを分解して見てみれば怖くない。
cat /dev/urandom | gtr -dc 0-9 | gfold -b2 | gsed 's/^0*//' | xargs -n 2 | gawk ' ($1*$1 + $2*$2) % ($1*$2+1) == 0 { # この条件に該当した場合に{}内を実行する a = ($1*$1 + $2*$2)/($1*$2+1); # 変数代入 "gfactor " a | getline x ; # factorコマンドで素因数分解した結果を変数xに格納する print $1,$2,x; # 出力 fflush() # バッファ出力 } ' | # 4 64 16: 2 2 2 2 のように右辺に素因数分解した結果が出力される gawk '{ for(i=4;i<=NF;i++) a[$i]++; # $iでi番目の値が取れる。上記の例でいうと、a[2]に4が入る。 printf $1" "$2" "$3; x="OK"; for(k in a){ if(a[k]%2 == 1) x="NG"; # 同じ値が2で割り切れない数繰り返された = 二乗にならない場合 } print x; }'
Q8分解
数列x_{i+1} = a * x_i * (1 - x_i)について、xの初期値を0.5としてAWKで出力して、百万回以上連続で、これまで出てきていない数字を出力してください。ただし、aは3以上、4未満の小数から選んでください。これに飽き足らない人は限界に挑戦してください。
これも何やっているか分解して考えれば怖くない。
cat /dev/urandom | gtr -dc 0-9 | gfold -b10 | gsed 's/^/0./' | # 0.xの数値をランダムに出す gawk '{print $1*4}' | gawk '$1>=3' | # 3以上4未満に揃える while read a ; # 入力がある限り繰り返す do gawk -v a=$a ' # シェル変数をawkの変数に代入 BEGIN{ OFMT="%.20f"; # 小数表示20桁とする(デフォだと指数表示になるため) x=0.5; # 数列の初期値を設定 while(1){ print x; # 数列の値を出力 x=a*x*(1-x) # 数列の次の値を計算 } } ' | head -n 1000000 | # 百万行出力 sort -u | # 重複を削除して並び替え wc -l | # それが何行あるか gawk -v a=$a ' $1==1000000 { # 百万行あれば print a,$1 # 出力する } '; done | head -n 1
npmでパッケージ公開するまでのコマンド
# npm設定確認 # レジストリのURLも確認できる npm config list # レジストリを変える npm set registry http://npm.example.com # レジストリ戻す npm set registry https://registry.npmjs.org/ # レジストリにユーザを追加 npm adduser --registry http://npm.example.com # ログインする # ~/.npmrc にログイン情報が保持されるので1回だけ叩けばOK npm login # パッケージのpublish npm publish # まちがえてpublishしたのを削除する npm unpublish <package-name>@<version>
npm レジストリサイト
https://www.npmjs.com/
class_evalを使って、classに自由な名前でメソッドを追加
concernに書くとこんな感じか。
# # include ::Logica::DateRangeSearchable # date_range_name_is :validity, :valid # # klass.valid # -> validity_start_at, validity_end_atが期間内のみ取り出す # instance.valid? # -> validity_start_at, validity_end_atが期間内か # module Logica module DateRangeSearchable extend ActiveSupport::Concern class_methods do def date_range_name_is(name, method_name = nil) method_name = name if method_name.blank? validation_name = "#{name}_start_lt_end_validation".to_sym validate validation_name class_eval <<-EOS def #{method_name}?(now = Time.zone.now) (self.#{name}_start_at.nil? || self.#{name}_start_at <= now) && (self.#{name}_end_at.nil? || self.#{name}_end_at >= now ) end def #{validation_name} if self.#{name}_start_at.nil? || self.#{name}_end_at.nil? return true end if self.#{name}_end_at <= self.#{name}_start_at message = I18n.t('errors.messages.less_than', count: self.#{name}_end_at) self.errors.add("#{name}_start_at".to_sym, message) end end def self.#{method_name}_conds(now = Time.zone.now) a = arel_table[:#{name}_start_at].lteq(now).or(arel_table[:#{name}_start_at].eq(nil)) b = arel_table[:#{name}_end_at].gteq(now).or(arel_table[:#{name}_end_at].eq(nil)) a.and(b) end EOS class_eval do scope method_name.to_sym, -> (now = Time.zone.now) { where(self.try("#{method_name}_conds", now)) } end end end end end