シェルワンライナーの軌跡
-
bc
計算するコマンド
sed
echo '小問1'
echo 'クロロメチルメチルエーテル' | sed 's/メ/エ/'
echo '小問2'
echo 'クロロエチルエチルエーテル' | sed 's/エチルエ/エチルメ/'
echo '小問3'
echo 'クロロメチルメチルエーテル' | sed 's/メチル/エチル/g'
echo '小問4'
echo 'クロロエチルエーテル' | sed 's/エチル/&&/'
echo '小問5'
echo 'クロロメチルエチルエーテル' | sed -E 's/(メチル)(エチル)/\2\1/'
- sedは置換コマンド
- 基本は一致した一箇所を置換
-
-g
オプションで一致箇所全て置換 -
&
は検索対処の文字を再利用できる -
-E
は拡張正規表現を利用
grep
- 検索コマンド
-
-o
オプションは正規表現にマッチした部分を切り出す -
-A 数値
正規表現にマッチした後何行かを表示する
awk
- awkはプログラミング言語でいろんな亜種がある
seq 5 | awk '/[24]/'
seq 5 | awk '$1%2==0'
seq 5 | awk '$1%2==0{printf("%s 偶数\n", $1)}'
seq 5 | awk '$1%2==0{print $1, "偶数"}$1%2{print $1, "奇数"}'
seq 5 | awk 'BEGIN{a=0}$1%2==0{print $1, "偶数"}$1%2{print $1, "奇数"}{a+=$1}END{print "合計", a}'
- 正規表現にマッチするものを抽出できる
-
$1
のようにして入力に入ってきた値を使える - 条件文を書くことでマッチしたものに絞れる
- printfもしくはprintで条件にマッチしたものを出力できる
- BEGINとENDで最初の行を処理する前と最後の行を処理した後の処理を書ける
- awkでは変数を宣言することなく使えるので上記の例ではBEGIN句は省略可
-
{a+=1}
の部分はルールがないので全行で処理される
- sort + uniqによる集計
- xargsによる1行並べ
- xargsの-nオプションで処理する引数の個数指定
- xargsの-Iオプションで引数にラベルをつける
- sedの
-nオプションと/正規表現/正規表現/p
を使用するとマッチする行のみ出力する - 画像拡張子変換に使える外部コマンド
convert
- xargsの-Pオプションで並列実行
- grepのRオプションで再起読み込み
- grepのlオプションはファイル名のみ欲しい時
-
${変数名^^}
で変数の値を全て大文字(bashのバージョンが古いと使えない) -
${変数名^}
で変数の先頭文字だけ大文字(bashのバージョンが古いと使えない) - sort -uでユニークにソートする
- wc -l で行数カウント
-
grep -f -
で標準入力から正規表現をよみこむ -
grep -x
行全体がマッチしないとマッチしたことにしない
% paste <( echo aaaa | grep -o .) <( echo bbbb | grep . -o)
a b
a b
a b
a b
-
paste
コマンドで出力を並べられる -
grep -o .
はマッチした部分を改行して並べるので横文字を縦文字に表示できる
paste <(cat "$kaibun" | grep -o .) <(cat "$kaibun" | grep -o . | tac) | awk '$1!=$2{a++}END{print (a > 0 ? "回文じゃないよ" : "回文だよ") }'
- tacは縦出力を逆に、revは横の出力を逆に
ruby ワンライナー
- rubyをワンライナーで実行する
ruby -e '<何かしらの処理>'
- 置換
ruby -pe 'gsub(<正規表現>) { $1 + $2.upcase }'
-
-p
オプションはsedのように行で処理する -
-n
オプションは-p
オプションと同様行を入力として処理する -
-l
オプションはputsなどに改行を挿入する -
-0
オプションはセパレーターに改行ではなくnull文字を使うようにする。sedのzオプションみたいなやつ。 -
-r
オプションはgemを使用したいときに指定 - 入力で入ってきた行は
$_
で扱える - rubyの正規表現はonigumoという正規表現ライブラリが使われており
\p{Han}
とすることで漢字とマッチさせることができる。 -
gsub
でパターンマッチを使うときはマッチした箇所の使用にはエスケープする
gsub(/\n([、。])/, "\\1\n")
rbコマンド
rbというコマンドが便利そうだったのでインストールした。
パスの通った場所に数行のrubyプログラムを置くだけ。
sudo sh -c 'cat > /usr/local/bin/rb <<"EOF"
#!/usr/bin/env ruby
File.join(Dir.home, '.rbrc').tap { |f| load f if File.exists?(f) }
def execute(_, code)
puts _.instance_eval(&code)
rescue Errno::EPIPE
exit
end
single_line = ARGV.delete('-l')
code = eval("Proc.new { #{ARGV.join(' ')} }")
single_line ? STDIN.each { |l| execute(l.chomp, code) } : execute(STDIN.each_line, code)
EOF'
- ホームディレクトリに
.rbrc
という設定ファイル?があれば読み込む - 指定できるオプションは
l
のみ -
-l
オプションがあれば行で処理する - 標準入力の値(行)に対してrubyの関数を実行する
-
-l
オプションがある場合は各行の値は文字列として、オプションがなければEnumerator
オブジェクトとして扱われる
// "Hello".lengthが実行されているn
% echo Hello | rb -l 'length'
5
// ["Hello"].firstが実行されている
% echo Hello | rb 'first'
Hello
#34
やまだ 山田
がんばる 頑張る
ばくはつする 爆発する
はげしい 激しい
これを漢字(ふりがな)
のようにワンライナーで置換する。
ruby -lne 'a=$_.match(/^(.*)(.*) (\p{Han}*)(\2)$/);puts "#{a[3]}(#{a[1]})#{a[2]}"' ../shellgei160/qdata/34/furigana.txt
#35
カタカナ5文字になったらアウト。その直前までの文字と文字数を出力。
.*
とすると最長一致になるので.*?
として最短一致。
% cat ../shellgei160/qdata/35/speech.txt | ruby -lne 'a=$_.match(/(^.*?\p{Katakana}{4})(?=[ア-ン])/);puts "#{a[1].length} #{a[1]}"'
25 21世紀に入ってからのIT業界を中心としたパラダイ
4 ジャスト
45 個人間であらゆるアセットをシェアするビジネスが注目を浴びており、共有経済、いわゆるシェアリ
22 顧客体験の高品質化、満足度、いわゆるサティス
#36
かっこが対応しているやつの文字だけ抽出する
とりあえず見やすいようにかっこの終わりで改行
sedの拡張がMacで使えなかったのでrubyのif文に正規表現でマッチするかを見てる
\g<1>
が正規表現の名前付き逆参照で、再帰的にチェックしてる(雰囲気で理解)
cat ../shellgei160/qdata/36/message.txt | sed 's/)(/)\n(/g' | ruby -ne 'puts $_ if /^(\(\g<1>\)|[^()]+)$/' | tr -d '()' | xargs | tr -d ' '
# 37
連続した文字を抽出
rubyでやろうとしたけどうまくできなかたので諦めてgnugrepをインストール
私は私は今、オーストラリアに
いるのですが、特に観光もせず、
部屋でシェル芸シェル芸の問題
問題を考えていますす。人それ
ぞれ、人生いろいろですよね。
cat ../shellgei160/qdata/37/diarydiary.txt | tr -d '\n' | ggrep -oE '(.+)\1'
# 38
普通にsedで置換
$ x='() { :;}; echo vulnerable' bash -c &amp;amp;amp;amp;amp;quot;echo this is a test&amp;amp;amp;amp;amp;quot;
vulnerable
this is a test
% cat ../shellgei160/qdata/38/this_is_it.txt | sed -E 's/\&(amp;)+quot;/"/g'
$ x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
# 39
30文字以上になったら折り返す
awkで頑張る
cat ../shellgei160/qdata/39/bash_description.txt | sed 's/ / \n/g;s/$/ /'| awk '{L+=length};L>31{print "";L=length}{printf $0}' | awk 'sub(/ $/,"")'
# 40
gemでzen_to_iを使う
gsubで改行+句読点を句読点+改行に置換する
cat ../shellgei160/qdata/40/kanjinum.txt | ruby -rzen_to_i -0ne 'print $_.zen_to_i.gsub(/\n([、。])/, "\\1\n")'
私が小学1年生の時は、
47都道府県の位置
と名前を全て覚えるくらいに
物覚えは良かったですが、
テストで100点満点を
取り、親から5000000000000000円を
プレゼントされることは
ありませんでした。
#41
markdownの注釈のペアが存在しないものを一覧表示
とりあえず拡張grepでタグを抽出
目印と注釈文がわかりやすいようにsedで加工
あとはsortとawkしたあとにuniqでペアが存在しないやつを一覧表示
uniqの-f1
で一列目を無視、-u
オプションが最初から一つしかない行を出力
ggrep -oE '\[\^.*\]:?' | sed 's/\]$/\] 目印/' | sed 's/\]:$/\] 注釈/' | sort | awk '{print $2,$1}' | uniq -f1 -u
# 42
markdownの連番をちゃんと連番にする問題
awkで連番正規表現にマッチしたらカウントしていたカウンタで置き換えてprint
#が出てきたらカウンタリセット
最後に連番以外の部分を!/正規表現/
で表示
awk '/^[0-9]\./{a++;$1=a".";print}/^#/{a=0}!/^[0-9]\./'
# 43
[4] トップページ | gihyo.jp, 技術評論社
https://gihyo.jp/
[3] シェル芸 | 上田ブログ
https://b.ueda.tech/?page=01434
[2] くんすとの備忘録
https://kunst1080.hatenablog.com/
[1] 日々之迷歩
https://papiro.hatenablog.jp/
[5] 俺的備忘録
https://orebibou.com/
これを番号順にソートする
3行ずつ記載されているのでとりあえず全行に目印つける
でソートする。ソートをそのまますると微調整がめんどくさくなるのでs
オプションで安定ソート。k
オプションで1列目を指定してソート
最後にsedで目印除去
awk 'NR%3==1{k=$1};{print k, $0}' | sort -s -k1,1 | sed 's/....//'
# 44
シェルスクリプトが含まれている行の行末に@を挿入する問題
一旦シェルスクリプトの前後に目印で%をつける
sedの拡張がMacで使えなかったのでrubyのgsubで置換
sedは%がある行の行末に@をつけて、最後に%決しておわり
ruby -0lne 'puts $_.gsub(/(シ\n?ェ\n?ル\n?ス\n?ク\n?リ\n?プ\n?ト)/, "%\\1%")' | sed '/%/s/$/ @/;s/%//g'
# 45
uniqの-Dが使えなくてguniqとしてインストールした
最初のawkで空行が消えて、null文字と行番号を付与
ソートして一回しかでない行は取り除く
最後のawkが想定通りにならないのはMacの標準awkだと挙動が違うのかもしれないけどけっこうはまったので飛ばした
awk 'NF{print NR, "\0"$0}' | sort -k2,2 | guniq -f 1 -D | sort -k1,1 -g | awk -F '\0' 'n+1!=$1{print t,"\0",ns;t=ns=""}{n=$1;t=t$2;ns=ns n}'
# 46
漢字に権利(けんり)
のようにルビをつける。
mecabのE
オプションは最後のEOFの出力を省く。
awkで漢字とふりがなを抽出、nkfでカタカナをひらがなに
rubyのgsubで置換してsedで余計なごみを削除
mecab -E '' | awk -F'[\t,]' '{print $1","$(NF-1)}' | nkf -h | ruby -lne 'puts $_.gsub(/(.*),(.*)\1/, "(\\2)\\1")' | sed 's/(\**)//' | xargs | tr -d ' '
# 47
前月比の列を追加する
awk -F',' '{printf $0","} NR > 1{rate=$2/last*100-100"%"; if(rate > 0)printf "+"; print rate}NR==1{print "*"} {last=$2}'
2017/01,108192,*
2017/02,134747,+24.5443%
2017/03,120420,-10.6325%
2017/04,147368,+22.3783%
2017/05,262456,+78.0957%
2017/06,280741,+6.96688%
2017/07,315083,+12.2326%
2017/08,522489,+65.8258%
2017/09,489003,-6.40894%
2017/10,729017,+49.0823%
2017/11,987173,+35.4115%
2017/12,1025320,+3.86427%
# 48
プロセス一覧からCPU使用率を集計して1番使っているユーザーを表示
ps aux | awk 'NR>1{p[$1]+=$3;n[$1]++}END{for(i in p) print p[i], n[i], i}' | sort -nrk 1,2
23.9 232 yamanakajunichi
10.5 2 _windowserver
0.9 86 root
0.8 4 _driverkit
0.4 2 _coreaudiod
# 49
topコマンドのログからCPU使用率が最も高いコマンドを集計して抽出する
ggrep -E '^ *[0-9]+ ' | awk '{x=$9;for(i=1;i<12;i++)$i="";a[$0]+=x}END{for(k in a)print a[k], k}' | sort -k1,1nr | head -n 5
# 50
2つのファイルを連結させて商品の売上金を計算する
joinで連結するときのkeyは2列では無理なので1列に加工して個数を集計
joinしていい感じにする
joinは引数に2つのファイルを受け付けるが、<()
でプロセス置換を使いsedの結果をファイル入力としている
2つ目の引数には-
を使うことで、前段のコマンド結果、つまり標準入力を受け付ける
columnコマンドは整形
cat ../shellgei160/qdata/50/sales | awk '{a[$3$4]+=$5}END{for(k in a)print k, a[k]}' | sort | join <(sed 's/ //' ../shellgei160/qdata/50/stones_master) - | awk '{print $2, $3*$4}' | column -t
#51
ファイルの結合
awkのsprintf
0埋めできる
joinの-a 1
は結合のキーがマッチしなかったときに一つ目のファイルをそのまま結合する
cat ../shellgei160/qdata/51/scores.txt | awk '{$1=sprintf("%03\d", $1);print}' | sort | join -a 1 ../shellgei160/qdata/51/students.txt - | awk 'NF==2{print $0, 0}NF==3'
# 52
% cat ../shellgei160/qdata/52/data_U
* A B
X 4 2
Y 3 1
% cat ../shellgei160/qdata/52/data_V
* A B C
X 7 6 -1
Y 9 8 -2
これら二つのクロス集計表を結合する。
awk 'FNR==1{$1="";h=$0}FNR!=1{print FILENAME, $0, h, NF-1}' ../shellgei160/qdata/52/data_U ../shellgei160/qdata/52/data_V | awk '{for(i=NF-$NF;i<NF;i++)print $1,$2,$i,$(i-$NF)}' | sed 's/.*data_//'
U X A 4
U X B 2
U Y A 3
U Y B 1
V X A 7
V X B 6
V X C -1
V Y A 9
V Y B 8
V Y C -2
# 53
joinの-a 1 -a 2
はSQLのフルジョインのようなもの
joinの-o
で出力フォーマット指定
joinの-e
で値がなかったときに代わりに出力する値を指定
% awk '{print $2, $1}' ../shellgei160/qdata/53/devicelist.txt | sort | join -a 1 -a 2 -o '1.2 0 2.2' -e @ - <(sort ../shellgei160/qdata/53/measurement.txt) | sort
01 xxxx.0c4d.1c45 1914
02 xxxx.0d46.f3c2 @
03 xxxx.0d17.73a6 2275
04 xxxx.0d81.33b8 @
05 xxxx.0d17.9658 @
06 xxxx.0c4d.095c 3235
07 xxxx.0a69.b711 3119
08 xxxx.0d81.1da2 @
09 xxxx.0fff.d828 3618
10 xxxx.0d17.7478 3443
@ xxxx.0d81.33a8 1607
@ xxxx.17d0.2c07 3431
# 54
% cat ../shellgei160/qdata/54/fruits.json | jq
{
"Fruits": [
{
"Name": "Apple",
"Quantity": 3,
"Price": 100
},
{
"Name": "Orange",
"Quantity": 15,
"Price": 110
},
{
"Name": "Mango",
"Quantity": 100,
"Price": 90
},
{
"Name": "Banana",
"Quantity": 6,
"Price": 100
},
{
"Name": "Kiwifruit",
"Quantity": 40,
"Price": 50
}
]
}
上記jsonをFruitsの各要素ごとにjsonファイルで切り出す
jq使いたくなるが意外と難しいのでrubyでやる
cat ../shellgei160/qdata/54/fruits.json | ruby -r json -e 'JSON.load(STDIN)["Fruits"].each{|fruit| File.open(fruit["Name"]+".json","w"){|file| file.write(JSON.pretty_generate(fruit))}}'
# 55
$ cat qdata/55/watch_log.json | head -n 1 | jq
{
"timestamp": "2020-01-18 18:06:52",
"output": "total 9888204\ndrwxr-xr-x 19 uesugi staff 608 1 12 23:22 .\ndrwxr-xr-x+ 86 uesugi staff 2752 1 18 18:06 ..\n-rw-r--r-- 1 uesugi staff 10244 1 7 00:57 .DS_Store\n-rw-r--r-- 1 uesugi staff 417254625 9 22 16:09 201812.tar.gz\n-rw-r--r-- 1 uesugi staff 54958837 9 22 16:10 201901.tar.gz\n-rw-r--r-- 1 uesugi staff 532549401 9 22 16:10 201902.tar.gz\n-rw-r--r-- 1 uesugi staff 399341189 9 22 16:11 201903.tar.gz\n-rw-r--r-- 1 uesugi staff 180073487 9 22 16:11 201904.tar.gz\n-rw-r--r-- 1 uesugi staff 599281846 9 22 16:11 201905.tar.gz\n-rw-r--r-- 1 uesugi staff 75347322 9 22 16:11 201906.tar.gz\n-rw-r--r-- 1 uesugi staff 271311958 11 3 19:47 201907.tar.gz\n-rw-r--r-- 1 uesugi staff 263584337 11 3 19:48 201908.tar.gz\n-rw-r--r-- 1 uesugi staff 4961687746 12 12 21:39 201909.tar.gz\n-rw-r--r-- 1 uesugi staff 2326560921 12 25 07:46 201910.tar.gz\ndrwxr-xr-x 19 uesugi staff 608 12 21 11:38 201911\ndrwxr-xr-x 22 uesugi staff 704 12 31 00:00 201912\ndrwxr-xr-x 21 uesugi staff 672 1 18 00:00 202001\nlrwxr-xr-x 1 uesugi staff 31 1 12 23:22 Project -> /Users/uesugi/Dropbox/Project\n-rw-r--r-- 1 uesugi staff 20119 1 18 17:04 memo.txt\n"
}
上記のようなJSONのoutputの差分を表示する
sedの2,$p
で2行目から最後までまで2回ずつ表示
sedの$d
で最後の行を削除
pasteの-d ,
でデリミタにカンマを指定してるので2行をカンマ区切りで一行で表示
次のsedで[]でくくる
whileループで変数lに行データを格納
jqで2つのデータのtimestampを並べる
diffにはプロセス置換で二つのデータのJSONのoutput部分を入力
むず
cat qdata/55/watch_log.json | sed '2,$p;$d' | paste -d , - - | sed 's/.*/[&]/' | while read -r l;do jq -r '"diff: \"\(.[0].timestamp)\" \"\(.[1].timestamp)\""' <<<$l; diff <(jq -r '.[0].output' <<<$l) <(jq -r '.[1].output' <<<$l);done
#56
アプリA: アクセス分析API, 交通情報API, 人事情報API
アプリB: 受注API, 交通情報API, 顧客情報API
アプリC: 受注API, メールAPI, 住所情報API
アプリD: 人事情報API, メールAPI
アプリE: 受注API, 交通情報API, 顧客情報API
住所情報API: 月, 水, 金
顧客情報API: 水, 日
交通情報API: 土
受注API: 火
アクセス分析API: 木
メールAPI: 金, 土
人事情報API: 月
上記ファイルをjoinする
最初のsedでsedの命令文を作る。区切り文字は/ではなく;を使用してる
次のsed -f -
で標準入力のsedコマンドをファイルに対して実行
あとはごにょごにょ
曜日のソートは一旦数字に置換してソートしたら元に戻す。なるほどなるほど
ちなみにsedのyは単純な文字列変換に使う。sは正規表現
$ cat qdata/56/service_stop_weekday.txt | sed -E 's;(.*):(.*);s/\1/\2/g;g' | sed -f - qdata/56/service_depend_list.txt | tr -d :, | awk '{for(i=2;i<=NF;i++)print $i,$1}' | sort -u | awk '{a[$1]=a[$1]" "$2}END{for(k in a)print k":"a[k]}' | sed 'y/月火水木金土日/1234567/' | sort | sed 'y/1234567/月火水木金土日/' | sed 's/ /, /g;s/,//'
月: アプリA, アプリC, アプリD
火: アプリB, アプリC, アプリE
水: アプリB, アプリC, アプリE
木: アプリA
金: アプリC, アプリD
土: アプリA, アプリB, アプリC, アプリD, アプリE
日: アプリB, アプリE
# 57
markdownのテーブル表示の縦棒をそろえる
% cat ../shellgei160/qdata/57/table.md | sed 's/|/ & /g' | column -t | sed 's/| /|/g;s/ |/|/g'
|AAA |BBB|CCC|
|--- |---|---|
|1 |123|4 |
|10000|1 |64 |
|3 |3 |3 |
# 58
桁区切りにカンマを使ってるcsvファイルの数値の和を求める
% cat ../shellgei160/qdata/58/num.csv | tr , ' ' | xargs -n 1 | sed 's/ //g' | xargs | tr ' ' + | bc
rubyでやってみた
% cat ../shellgei160/qdata/58/num.csv | tr , ' ' | xargs -n 1 | sed 's/ //g' | ruby -rbigdecimal -lne 'puts ARGF.map{|n| BigDecimal(n)}.sum.to_s("F")'
1235361.19999999999999999999999
# 59
csvの行数が違う行を出力
rubyのCSVライブラリを使用
% cat ../shellgei160/qdata/59/data.csv | ruby -rcsv -e 'CSV.parse(STDIN) {|row| p row.length}' | awk '$1==2{print NR}'
# 60
2017-2-24からその年末までのプレミアムフライデーを抽出
例のごとくgdateを使う(-dオプションを使うため)
% seq 0 365 | xargs -I@ gdate '+%F %a' -d '2017-2-24 @day' | grep '^2017' | grep '金$' | tac | guniq -w7 | tac
2017-02-24 金
2017-03-31 金
2017-04-28 金
2017-05-26 金
2017-06-30 金
2017-07-28 金
2017-08-25 金
2017-09-29 金
2017-10-27 金
2017-11-24 金
2017-12-29 金
# 61
Mac標準のfindコマンドだと-daystart
オプションはない
現在日時の先週に更新されたファイル一覧
find . -daystart -mtime -$(( 8 + $(gdate '+%w') )) -mtime +$(gdate '+%w') -type f
# 62
祝日リストを使って2019-01-01から2021-12-31のリストを作成する
nkfでとりあえず読めるように表示(-wLux
でとりあえずutf8で)
tailで2行目以降、つまり先頭行とばす
teipは指定の列にのみコマンドを適用する。-d,
で区切り文字にカンマを指定し、-f 1
で1列目にコマンドを適用。
awkで絞ってcatで日付のシーケンスと結合、あとはごにょごにょ
nkf -wLux | tail -n +2 | teip -d, -f 1 -- gdate -f- '+%Y-%m-%d' | awk -F- '$1>=2019&&$1<2022' | cat - <(dseq 2019-01-01 2021-12-31 | sed 's/$/,@/') | sort -r | guniq -w10 | tac
# 63
5週ある月を抽出
% dseq 2021-01-01 2021-12-31 | gdate -f- | awk '$1=="日"{a[$2]++}END{for(k in a)print k, a[k]}' | awk '$2==5' | sort -n
1 5
5 5
8 5
10 5
# 64
第三火曜日を抽出
% dseq 2021-01-01 2021-12-31 | gdate -f- '+%m %d %a' | grep '火$' | awk '{a[$1]=a[$1]","$0}END{for(k in a)print a[k]}' | sed 's/^,//' | awk -F, '{print $3}' | sort -n
01 19 火
02 16 火
03 16 火
04 20 火
05 18 火
06 15 火
07 20 火
08 17 火
09 21 火
10 19 火
11 16 火
12 21 火
# 65
62で使った祝日表を使って2019年の休日の数を数える
ひたすら置換
% cat ../shellgei160/qdata/62/syukujitsu.csv | nkf -wLux | tail -n +2 | teip -d, -f 1 -- gdate -f- '+%Y-%m-%d %a' | awk -F- '$1==2019' | cat - <(dseq -f '%Y-%m-%d %a' 2019-01-01 2019-12-31 |sed -e 's/Mon/月/' -e 's/Tue/火/' -e 's/Wed/水/' -e 's/Thu/木/' -e 's/Fri/金/' -e 's/Sat/土/' -e 's/Sun/日/' | sed 's/$/,@/') | sort -r | guniq -w10 | sed 's/,/ /' | awk '$2=="土"||$2=="日"||$3!="@"{print $0}' | awk -F'-' '{a[$2]++}END{for(k in a)print k"月", a[k]}' | sort
01月 10
02月 9
03月 11
04月 10
05月 12
06月 10
07月 9
08月 10
09月 11
10月 10
11月 10
12月 9
# 66
指定の日時のMTGが何回もリスケになりました
nextwd
標準入力で受け付けた日時の翌週の指定の曜日の日付を出力するコマンドを作成する。
#!/bin/sh
nextwd() {
read d
date -d '' > /dev/null 2>&1
if [ "$?" -eq 0 ];then
date -d "$d $((7 - $(date -d $d +%w) + $(date -d $1 +%w))) day" +%F
exit 0
fi
if command -v gdate > /dev/null; then
gdate -d "$d $((7 - $(gdate -d $d +%w) + $(gdate -d $1 +%w))) day" +%F
exit 0
fi
echo 'not found gdate command or not use `-d` option.'
exit 1
}
nextwd "$@"
chmod +x ./nextwd.sh
sudo mv ./nextwd.sh /usr/local/bin/nextwd
% echo 2017-09-18 | nextwd Tue
2017-09-26
回答
echo 2017-09-18 | nextwd Tue | nextwd Fri | xargs -I@ gdate -d '@ yesterday' +%F
2017-10-05
# 67
20190101 たまごかけごはん
20190102 納豆ごはん
20190105 焼肉
20190106 断食
20190107 焼肉
20190108 たまごかけごはん
20190110 ミートボールスパ
20190111 ニシンのパイ
20190113 断食
20190114 焼肉
曜日ごとにメニューを書き出す
cat ../shellgei160/qdata/67/dinner | teip -f 1 -- gdate -f- '+%F %a' | awk '{print $3 > $2}'
# 68
利用できるUnix時刻の最大値を求める
f=0;t=$(bc <<< 2^90);while [ $(bc <<< $t-$f) != 1 ];do m=$(bc <<< "($f+$t)/2"); echo $m; gdate -d @$m && f=$m || t=$m;done
# 69
うるう秒のあった日の列挙
以下が正解らしいがMacだとrightプレフィックスのタイムゾーンが使えなそう
printf "%s 9 1sec ago\n" {1970..2017}-{01,07}-01 | TZ=right/Japan gdate -f- | grep :60
# 70
テキストをエクセル方眼紙にするために変換
cat ../shellgei160/qdata/70/excel_hogan.txt | sed 's/./&_/g' | sed 's/"/""""/g' | sed 's/,/","/g' | tr _ , | nkf -sLwx > hoge.txt
文字コード
uniname
Unicodeの文字列を解析するコマンド
brew install uniutils
echo a | uniname
nkf
utf8 -> sjis
nkf -sLwx
-
-s
sjisへの変換 -
-Lw
改行をLF -> CRLF -
-x
半角カタカナ->全角を抑止する
もしutf8->sjisでうまくいかないことがあったら-S
をつけてsjisであることを明記するとうまくいくかも
sjis -> utf8
nkf -wLux
-
-w
utf8への変換 -
-Lu
改行をCRLF->LF
#71
各文字のバイト数を出力する
% cat ../shellgei160/qdata/71/uni.txt | grep -o . | while read -r s;do echo -n "$s";echo -n $s | wc -c;done
a 1
± 2
運 3
🎂 4
#72
絵文字をUnicodeで出力する
echo -e '\U1F363\U1F37A'
🍣🍺
# 73
windows環境で作成したzipファイルの文字化けをなおす
# 74
日付に元号をつける
元号の合字のUnicodeが存在する
令和: U+32FF`` 平成:
U+337B```
awkの-F
で[^0-9]
を指定すると区切り文字を正規表現で指定することになり、この場合、数字以外の任意文字が区切りとなり、結果として数字だけを抽出できる、みたい
cat ../shellgei160/qdata/74/days.txt | awk -F'[^0-9]' '{printf "%d %02d %02d\n", $1, $2, $3}' | awk '{if($1$2<"201905"){a="337B";$1-=1988}else{a="32FF";$1-=2018}print "echo -e \\\\U"a,$1"年",$2"月",$3"日"}' | bash | sed 's/ 1年/ 元年/' | tr -d ' ' | sed 's/年0/年/;s/0月/月/'
㍻31年3月03日
㋿元年1月10日
㋿2年8月01日
# 75
絵文字を消去する
nkfに2回通すだけ
絵文字はUnicodeにしか存在しないのでsjisにすると絵文字が消去される。
その後、utf8に戻すと絵文字が消えている
cat ../shellgei160/qdata/75/minutes.txt | nnkf -s | nkf -w
rb使った別解
% cat ../shellgei160/qdata/75/minutes.txt | rb 'each{|row|puts row.gsub(/[^#*\P{Emoji}]\u200d?/,"")}'
[^#*\P{Emoji}]
が二重否定になっていて絵文字以外の文字に#とを加えたものを否定することで絵文字がマッチする。\p{Emoji}
で絵文字にマッチできるがや#といった一部の記号も含まれてしまっているので二重否定を使用している。
\u200d
はゼロ幅接合しと呼ばれる特殊なメタ文字で絵文字同士を結合させる。
以下のようにメタ文字を消去すると絵文字が分解される
% echo 👨<200d>👩<200d>👧<200d>👦
👨👩👧👦
% echo 👨<200d>👩<200d>👧<200d>👦 | sed s_$(echo -ne \\U200d)__g
👨👩👧👦
#76
少し前のMacのファイルシステムは**HFS+**というものが採用されており、簡単に言うと濁音や半濁音の点や丸を分けることができる。見た目はわからないけど
なので以下のようにdiffをとると差分がでない
diff ../shellgei160/qdata/76/mac_ls_old.txt ../shellgei160/qdata/76/mac_ls_new.txt
1,3c1,2
< ポンセ.txt
< バナザード.txt
< パチョレック.txt
---
> ポンセ.txt
> パチョレック.txt
nkf -Z4 ../shellgei160/qdata/76/mac_ls_old.txt | nkf | diff - ../shellgei160/qdata/76/mac_ls_new.txt
2d1
< バナザード.txt
上記のようにnkf -Z4
で半角に戻し、もう一度nkfを通し全角にすることで差分がちゃんと出る
# 77
文字コードが異なるファイル群から検索する
ggrep -a
は非UTF8の文字を検索するためのオプション。-H
は検索結果にファイル名を表示する。
% ls ../shellgei160/qdata/77/meme_* | xargs -I@ sh -c 'ggrep -aH . @ | nkf' | grep 山田 | sed 's_../shellgei160/qdata/77/__' | sed 's/:.*//'
meme_euc
meme_utf8
# 78
漢字を抽出して常用漢字以外を抽出する
文字列から正規表現にマッチした箇所を抽出するにはsliceでできるが複数マッチにはscanを使う
先頭要素にマッチした箇所全部入ってるのでuniqで重複箇所を削除しておく
grep -f
で常用漢字表を検索条件にして検索した結果を反転することで常用以外の漢字を出力
% cat ../shellgei160/qdata/78/sample_novel.txt | rb -l 'scan(/\p{Han}/).uniq' | ggrep -vf ../shellgei160/qdata/78/jouyou_kanji.txt
智
皰
噛
云
鴎
# 79
文字化けをなおす
nkfの自動判別でだめなのでiconvを使用する
iconv -lで対応している文字コードを一覧出力し、iconvに通す。
エラーにならなかったものからひらがな、カタカナ、漢字が含まれるものを抽出し、再度iconvに通す
これでうまくいくはずなんだけど想定通りにならなかった
iconvの挙動が解答と違いそう
% iconv -l | while read c;do iconv -f $c ../shellgei160/qdata/79/message.txt &> /dev/null | ggrep -qP '\p{Hiragana}|\p{Katakana}|\p{Han}' && echo $c && iconv -f $c ../shellgei160/qdata/79/message.txt;done
バイナリ操作
% echo 🍣🍺 | iconv -f UTF-8 -t UTF-32 | xxd
00000000: 0000 feff 0001 f363 0001 f37a 0000 000a .......c...z....
- 絵文字をUTF-8からUTF-32に変換して
xxd
に通す - 行頭の
00000000:
はオフセットと呼ばれるもので当該の行がどの位置のデータに相当するかを表す -
.......c...z....
は実際の文字だが文字化けしてるのでほとんど情報はもたない - 寿司のコードポイントは
U+1F363
- このデータを
0001F363
とするか63f30100
とするかはCPUが先に読む方を下からか上からかという話と関係があり、どちらからか読むかをバイトオーダーという。 - 下から読むのをリトルエンディアン、上から読むのをビッグエンディアン と呼ぶ。
- UTF-32やその他のいくつかの種類のテキストデータは、バイトオーダーを明示するためにBOMという特別なバイト列が先頭に記述されている。
-
0000 feff
の部分がBOM。この場合、高い方からでビッグエンディアン - 以下のようにするとリトルエンディアン
% echo 🍣🍺 | iconv -f UTF-8 -t UTF-32LE | xxd
00000000: 63f3 0100 7af3 0100 0a00 0000 c...z.......
# 80
2進数の文字を元に戻す
obase=16
で出力を16進数、ibase=2
で入力を2進数にしてbcに通す
xxdの-r
はリバースでデコードするため、16進数の文字をデコードし元の文字を表示する
% cat ../shellgei160/qdata/80/zeroone | sed 's/^/obase=16;ibase=2;/' | bc | xxd -p -r
不労所得
#81
BOMが含まれていれば[BOM]
を挿入する。
BOMは3バイトで0xEFBBBF
なので置換して再度xxd
でデコードする
% cat qdata/81/bom.txt | xxd -p | sed "s/^efbbbf/$(echo -n '[BOM]' | xxd -p)/" | xxd -p -r
[BOM]ボムボムプリンおいしい
# 82
でかいファイルを分割する。1000mごとに分割。
% gsplit -b 1000 -d -a 2 qdata/82/image.bmp image.bmp.
-d
で連番suffix指定、-a 2
でsuffixの長さ指定
# 83
SJISで書かれたシェルスクリプトを実行する
% ./qdata/83/soleil.bash | iconv -f SJIS -t UTF8
親戚のャ激Cユちゃんは撫
iconv: (stdin):1:23: cannot convert
SJISから変換してもうまく表示できない
SJISは2バイトで日本語を表示する。このとき0x5c
はASCIIコードで半角のバックスラッシュと一致する。そのため、例えば「ソ」は0x835c
となっているため2バイト目のコードがバックスラッシュとして認識され無視される。このような問題が発生する文字はダメ文字と呼ばれ、5c問題と言われている。
この解答はバックスラッシュを増やして置換することで解決できる。
% cat ./qdata/83/soleil.bash | sed 's/\\/\\\\/g' > new_soleil.bash
# 84
# 85
#90
基数の違う数字の計算
% printf "0x%x\n" $(( 4#12 + 8#34 + 16#56 ))
0x78
4進数、8進数、16進数を算術式展開で計算し、printfで16進数として出力
# 91
2,3,5,7の数字を使ってその辺の長さの三角形を作るときの組み合わせが何通りか。
% echo {2,3,5,7}{2,3,5,7}{2,3,5,7} | xargs -n 1 | awk '$1<=$2&&$2<=$3' FS= | awk '($1+$2)>$3' FS= | wc -l
14
awkでFS=
とするとセパレーターに空文字を指定したことになり一文字ずつ変数に格納されることになる。
# 92
0.01mmの厚さの紙を半分に折り曲げていき1000kmを超えるには何回折り曲げればいいか。
% yes | awk '0.01*(2^NR)>1000^3{print NR;exit}'
yes
コマンドは永遠にy
を出力する。
パイプで繋いだawkではこのyは使わず行番号を使い、指数計算をして1000kmを超えたらprintしてexit
# 93
2019年1 月1日0時0分0秒以後、初めて素数になるとき
% seq 0 inf | sed 's/.*/2019-01-01 00:00:00 & sec/' | gdate -f - '+%Y%m%d%H%M%S' | factor | awk 'NF==2{print $2;exit}'
0から無限に整数を出力してdateに通せするような文字列をsedで生成して、最後は素因数分解。
# 94
0から100まででn = a^2 + b^2 + c^2 + d^2
を満たす組み合わせを全てのnに対して表示する。
とりあえず、a,b,c,dで一つでも10以上があると100を超えてしまうので0-9の範囲でa,b,c,dの組み合わせ全通りを考えてそこからnが0-100のものを抽出する方向で考える。
% seq -w 0 9999 | awk '{print $0, $1*$1+$2*$2+$3*$3+$4*$4}' FS= | sort -k2,2n | uniq -f 1 | head -n 101
# 95
# 96
% awk '{filename = FILENAME;sub(".*/", "", filename);print $0, filename}' ./qdata/96/user* | sort | awk '{a[$1]=a[$1]" "$2}END{for(k in a)print k, a[k]}' | awk 'NF==4{print $0}'
2019/07/10 user1 user2 user3
2019/07/15 user1 user3 user4
# 97
% cat qdata/97/tate.txt
このたびの私の寝坊及び早弁について
とっても反省しておりますので、
給与よんばいで許してください。
許せみんな。
縦読みするとたてよみになる列のはじめの行番号と列番号を出力する
% cat qdata/97/tate.txt | rb 'a=map{|l|l.chomp.split("").concat([""]*20)[0..20]}.transpose.map{|l|l.join}' | rb -l 'i=index(/たてよみ/);"#{i+1} #{$.}" if i' | awk NF
# 98
comm
コマンドでプロセス置換で入力した二つのファイルの共通する行、片方にしかない行を表示できる。 1列目がlist1にしかない値、2列目がlist2にしかない値、3列目が共通する値
% comm <(sort qdata/98/list1) <(sort qdata/98/list2)
シァル芸
シェノ芸
シェル芸
シェレ芸
シュル芸
ンェル芸
この値はタブで区切られてるのでタブを区切り文字に配列にしてごにょごにょ
% comm <(sort qdata/98/list1) <(sort qdata/98/list2) | rb -l 'a=split("\t");i=a.size;file=i==3?"common":"oneside";File.open(file, "a"){|f| f.puts "#{a[i-1]}"}'
% head common oneside
==> common <==
シェノ芸
シェル芸
シェレ芸
ンェル芸
==> oneside <==
シァル芸
シュル芸
#99
ポーカーの役でフラッシュの行を見つける
% cat qdata/99/cards.txt | rb 'select {|l| /^([♥♦♣♠]) \d+ \1 \d+ \1 \d+ \1 \d+ \1 \d+$/.match(l)}'
♣ 7 ♣ 8 ♣ 9 ♣ 11 ♣ 13
♥ 8 ♥ 9 ♥ 10 ♥ 11 ♥ 12
♠ 9 ♠ 10 ♠ 11 ♠ 12 ♠ 13
フルハウス
% cat qdata/99/cards.txt | rb 'select {|l| /^. (\d+)( . \1){1,2} . (\d+)( . \3){1,2}$/.match(l)}'
♣ 5 ♦ 5 ♣ 11 ♠ 11 ♥ 11
♠ 3 ♣ 3 ♥ 3 ♣ 11 ♦ 11
♥ 2 ♦ 2 ♠ 13 ♣ 13 ♥ 13
# 100
しりとりになるように出力
% join -j9 qdata/100/shiritori.txt{,} | ggrep '\(.\) \1' | gtsort 2>/dev/null
けんこう
うしみつどき
きゅうけい
いちょう
うがい
いんどあ
あけがた
join -j9は9列目の値でjoinだけど、9列目がない場合はキーなしでジョインする
そのあとにgrepの正規表現でしりとりになってるやつを抽出
# 101
% cat qdata/101/alphabet_connection
b c f i j k l p e q r u w a y z
上記ファイルを連続したファルファベットを````a-c```のように加工して出力。
% cat qdata/101/alphabet_connection | tr ' ' '\n' | sort | comm - <(echo {a..z} | tr ' ' '\n') | awk -F"\t" '{print $3}' | ruby -0777 -pe 'gsub(/([a-z])(\n[a-z])*\n([a-z])/m, "\\1-\\3")' | xargs
a-c e-f i-l p-r u w y-z
rubyの-0777
はsed -z
の代わりで、入力レコードのセパレーターを変更している。全行にまたいで置換するため。-n
ではなく-p
なのは置換結果を出力するため。
# 102
# 108
ログファイルからプロセスキルされたプロセスを探して集計する
% gzcat syslog.gz | grep Killed | awk '{print $10}' | tr -d '()' | awk '{a[$1]+=1}END{for(k in a)print k, a[k]}'
superapp 9
最後の集計はsortしてuniqでもいいけど件数が多くなるとawkの方が早い
% gzcat syslog.gz| grep invoked | sed -E 's/(.*) invoked .*/\1/' | sed 's/^.*[0-9]] //' | sort | uniq -c | sort -r
3 apache2
2 gmain
1 tmux: server
1 systemd-network
1 lsb_release
1 apport
tmux: server
というプロセス名がやっかいなのでsedで前後削除してプロセス名だけ抽出する。
# 109
/etc配下の同じファイル名のファイル
% sudo find /etc/ -type f | sudo xargs md5sum | awk '{a[$1]=a[$1]" "$2}END{for(v in a)print v, a[v]}' | awk 'NF>2'
md5でハッシュ化してawkの連想配列に格納して重複してるやつだけ出力
# 110
/var/logs
配下のディレクトリごとのファイル数を集計
% sudo find /var/log -type d | while read d;do echo -n $d" ";find "$d" -type f -maxdepth 1 | wc -l;done
# 134
pythonのファイルでインデントが4の倍数でない行を出力
awkのmatch関数で先頭空白の行にマッチさせる。マッチした長さはRLENGTH
という変数に格納される。awkのif文は0がtrueでそれ以外はfalseとされるため、4の倍数以外のときにprintが実行される。
% cat 134/hoge.py | awk 'match($0, /^ +/){if(RLENGTH%4)print NR}'
5
# 135
% cat 135/sample.lisp
; n!(階乗)を返す
(defun fact (n) (if (<= n 1) 1 (* n (fact (- n 1)))))
; n番目のフィボナッチ数を返す
(defun fib (n) (if (<= n 1) n (+ (fib (- n 1) (fib (- n 2)))))
; 1からnまでの総和を返す
(defun sum1 (n) (if (<= n 1) n (+ n (sum1 (- n 1))))
;; 実行
(format t "fact:~D~%fib:~D~%sum1:~D"
(fact 5)
(fib 5)
(sum1 5))
このLispファイルの関数定義のかっこの数があってない関数名を出力
% cat 135/sample.lisp | grep '^(defun' | awk '{if(gsub(/\(/, "&", $0) != gsub(/\)/, "&", $0)){print $2}}'
fib
sum1
# 136
コードを入れ替える。
% cat 136/somecode.c | ruby -0777 -pe 'gsub(/(int b.+)(void a.+)(main.+)/m, "\\2\\1\\3")'
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void a()
{
int i = 0, j = b();
for (; i < j; i++){
puts("a");
}
}
int int b()
{
return rand()%10;
}
main(int argc, char const *argv[])
{
srand(time(NULL));
a();
return 0;
}
# 137
コードをフォーマットする。
% cat 137/fib.c | sed 's/[{}]/\n&\n/g' | cat -s | ruby -ne 'i ||= 0;i -= 1 if $_.match(/^}/);print "\t" * i;puts $_;i += 1 if $_.match(/^{/)'
#include <stdio.h>
int fib (int n)
{
if(n <= 1)
{
return n;
}
return fib(n-1)+fib(n-2);
}
int main (void)
{
int i;for(i=0;i<10;i++)
{
printf("%d\n",fib(i));
}
return 0;
}
最初のsedで{}
の前後で改行。rubyで{}
の数をカウントしながらタブを行頭に入れる。
# 138
% cat 138/browser.csv 138/os.csv 138/service.csv | ruby -lne 'BEGIN{a={}};$_.split(",").each{|val| a[$.]||=[];a[$.] << val};END{a[1].each{|br|a[2].each{|os|a[3].each{|sv|puts "#{br} #{os} #{sv}"}}}}' | grep -v 'IE [macOS|Linux]' | grep -v 'Safari [Windows|Linux]'
rubyで連想配列に格納することでos, ブラウザ,サービスごとに分けてループして全組み合わせ作る。
あとはgrepで排除したい組み合わせを指定。
# 139
% echo https://{example,cc.bb.aa.example.com,bb.aa.example.com,aa.example.com}/{A,A/B,A/B/C} | sed 's/ /\n/g'
https://example/A
https://example/A/B
https://example/A/B/C
https://cc.bb.aa.example.com/A
https://cc.bb.aa.example.com/A/B
https://cc.bb.aa.example.com/A/B/C
https://bb.aa.example.com/A
https://bb.aa.example.com/A/B
https://bb.aa.example.com/A/B/C
https://aa.example.com/A
https://aa.example.com/A/B
https://aa.example.com/A/B/C
# 140
# 147
% cat page | ggrep -zoP '<td[^<]*>.*?</td>' | tr \\0 \\n | sed -E 's/<[^<]*>//g' | mecab | awk '{a[$1]++}END{for(k in a)print k, a[k]}' | sort -k2,2nr | head -n 5
EOS 195
シェル 84
芸 78
が 74
月 69
grepでtdタグだけ抽出して、念のため-z
オプションで改行が含まれていても1行にするようにして、みやすいようにnull文字を改行に戻して、タグをsedではずして、mecabで形態素解析してawkで集計
# 148
路線情報APIから指定の路線の駅名を出力
% curl http://file.ueda.tech/eki/l/11303.json | jq '.station_l[].station_name'
"川崎"
"尻手"
"矢向"
"鹿島田"
"平間"
"向河原"
"武蔵小杉"
"武蔵中原"
"武蔵新城"
"武蔵溝ノ口"
"津田山"
"久地"
"宿河原"
"登戸"
"中野島"
"稲田堤"
"矢野口"
"稲城長沼"
"南多摩"
"府中本町"
"分倍河原"
"西府"
"谷保"
"矢川"
"西国立"
"立川"
"八丁畷"
"川崎新町"
"小田栄"
"浜川崎"
# 149
天気予報
% curl wttr.in/Tokyo
Weather report: Tokyo
\ / Sunny
.-. 19 °C
― ( ) ― → 17 km/h
`-’ 10 km
/ \ 0.0 mm
┌─────────────┐
┌──────────────────────────────┬───────────────────────┤ Wed 22 Nov ├───────────────────────┬──────────────────────────────┐
│ Morning │ Noon └──────┬──────┘ Evening │ Night │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ \ / Sunny │ \ / Sunny │ \ / Partly cloudy │ _`/"".-. Patchy rain po…│
│ .-. 19 °C │ .-. 19 °C │ _ /"".-. 19 °C │ ,\_( ). 19 °C │
│ ― ( ) ― ↗ 18-24 km/h │ ― ( ) ― → 21-27 km/h │ \_( ). ↗ 5-7 km/h │ /(___(__) ↗ 5-7 km/h │
│ `-’ 10 km │ `-’ 10 km │ /(___(__) 10 km │ ‘ ‘ ‘ ‘ 10 km │
│ / \ 0.0 mm | 0% │ / \ 0.0 mm | 0% │ 0.0 mm | 0% │ ‘ ‘ ‘ ‘ 0.0 mm | 71% │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
┌─────────────┐
┌──────────────────────────────┬───────────────────────┤ Thu 23 Nov ├───────────────────────┬──────────────────────────────┐
│ Morning │ Noon └──────┬──────┘ Evening │ Night │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ \ / Sunny │ \ / Partly cloudy │ \ / Clear │ \ / Clear │
│ .-. 19 °C │ _ /"".-. 19 °C │ .-. 19 °C │ .-. 20 °C │
│ ― ( ) ― → 21-27 km/h │ \_( ). → 29-37 km/h │ ― ( ) ― ↗ 37-47 km/h │ ― ( ) ― ↗ 43-55 km/h │
│ `-’ 10 km │ /(___(__) 10 km │ `-’ 10 km │ `-’ 10 km │
│ / \ 0.0 mm | 0% │ 0.0 mm | 0% │ / \ 0.0 mm | 0% │ / \ 0.0 mm | 0% │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
┌─────────────┐
┌──────────────────────────────┬───────────────────────┤ Fri 24 Nov ├───────────────────────┬──────────────────────────────┐
│ Morning │ Noon └──────┬──────┘ Evening │ Night │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ \ / Sunny │ \ / Sunny │ \ / Clear │ \ / Clear │
│ .-. 19 °C │ .-. 17 °C │ .-. +14(10) °C │ .-. +13(9) °C │
│ ― ( ) ― → 63-78 km/h │ ― ( ) ― → 69-81 km/h │ ― ( ) ― → 79-91 km/h │ ― ( ) ― → 74-85 km/h │
│ `-’ 10 km │ `-’ 10 km │ `-’ 10 km │ `-’ 10 km │
│ / \ 0.0 mm | 0% │ / \ 0.0 mm | 0% │ / \ 0.0 mm | 0% │ / \ 0.0 mm | 0% │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
Location: 東京都, 日本 [34.2255804,139.294774527387]
Follow @igor_chubin for wttr.in updates
# 150
ソフトウェアデザインの2022年で品切れの号を出力
% curl -s https://gihyo.jp/magazine/SD/backnumber | grep -B3 品切 | grep '^<h3' | sort | sed 's/<[^>]*>//g' | grep 2022
Software Design 2022年5月号
Software Design 2022年6月号
Software Design 2022年7月号
Software Design 2022年8月号
Software Design 2022年9月号
Software Design 2022年10月号
Software Design 2022年11月号
Software Design 2022年12月号
# 151
駅情報APIと地理情報APIを使って山手線の駅を標高昇順で表示
% curl -s http://file.ueda.tech/eki/l/11302.json | ruby -rjson -0777 -ne 'JSON.parse($_)["station_l"].each{|row|puts row["station_name"], row["lon"], row["lat"]}' | xargs -n3 sh -c 'printf "$0 ";curl -s "https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=$1&lat=$2&outtype=JSON" | jq ".elevation"' | sort -k2,2n
有楽町 2.8
品川 3.1
高輪ゲートウェイ 3.1
御徒町 3.3
田町 3.4
新橋 3.6
東京 3.6
大崎 3.8
秋葉原 3.8
五反田 3.9
浜松町 4.3
神田 4.6
田端 6
日暮里 6.3
鶯谷 8.9
上野 11.3
西日暮里 12.4
渋谷 15.5
駒込 16.6
大塚 19.1
恵比寿 20.4
巣鴨 21.9
高田馬場 22.3
目白 25
原宿 28.4
目黒 29.7
池袋 32.5
代々木 34.9
新大久保 35
新宿 37.5
# 152
HTTPステータスコードで出力文字を変える
% while sleep 5;do curl -I -s example.com | head -n 1 | awk '$2==200{print "Success!"}$2!=200{print "Fail!!"}';done
Success!
# 153
telnetで通信する
% ( printf 'HEAD / HTTP/1.1\nHost: www.google.co.jp\n\n';sleep 1) | telnet www.google.co.jp 80
Trying 2404:6800:4004:823::2003...
Connected to www.google.co.jp.
Escape character is '^]'.
HTTP/1.1 200 OK
レスポンスが返ってくる前に処理が終了してしまうのでsleepで1秒くらい待つ。
HTTPSの場合はopensslを使う。
% ( printf 'HEAD / HTTP/1.1\nHost: www.google.co.jp\n\n';sleep 1) | openssl s_client -connect www.google.co.jp:443 -quiet -no_ign_eof
# 155
HTTPレスポンスを返すサーバーをワンライナーで立てる。そしてレスポンスのデータサイズと異なるContent-Lengthを指定する。
% (echo -e "HTTP/1.1 200 OK\nContent-Length: 5";echo;printf test) | nc -N -l 8080
# 156
ドメインの一覧から複数IPを持つドメインのみ抽出する。
% cat shellgei160/qdata/156/domains.txt | xargs dig +noall +answer | awk '{print $1}' | uniq -d | sed 's/\.$//'
# 157
pingのパケット解析をする。
# 160
サーバー証明書から有効期限を取得して表示する。
% openssl s_client -connect example.com:443 < /dev/null 2>/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' | openssl x509 -text | grep -A 1 'Not Before'
Not Before: Jan 13 00:00:00 2023 GMT
Not After : Feb 13 23:59:59 2024 GMT