たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

シェル芸160ノック5

9月末に発売されたシェル芸本の続きです。問題21をやっていたらzshexpnを読み込むことになってしましました。できることが多いですね。

gihyo.jp

前回はこちら

xztaityozx.hatenablog.com

問題21

$  (cd qdata/21; fd --type=f --exclude="dir_b/d*" . ./)
dir_a/file_1
dir_a/file_2
dir_b/file_1
dir_b/file_2
dir_c/dir_b/dir_a/file_1
dir_c/dir_b/file_1
dir_c/dir_b/file_2

github.com

zshのglobなら

$ ls -1 **/*~dir_b/dir_*/f*(.) | sort
dir_a/file_1
dir_a/file_2
dir_b/file_1
dir_b/file_2
dir_c/dir_b/dir_a/file_1
dir_c/dir_b/file_1
dir_c/dir_b/file_2

問題22

$ echo {www,login,blog,admin,unko,hoge,fuga}.{unko,unchi,super,unk}.{co.jp,com,net,xyz}

ダミー文字列と言われたときにunkoが先に出てくるの、シェル芸のせいだと思います。

問題23

# 端末1
$ echo $$
9
$ kill -19 $$

# 端末2
$ kill -18 9

問題24

$ function zshexit() { rm -rf ~/tmp/* }

問題25

$ sort | awk 'NR==1,NR==10'

シェル芸160ノック4

シェル芸本の続きです。今回はシェルの機能を使おう!というセクションだったのでmanを探検するなどしました。

gihyo.jp

前回はこちら

xztaityozx.hatenablog.com

問題16

$ n=XYZ;(for i in {A..C}; do n+=$i;echo $n;done);echo $n
XYZA
XYZAB
XYZABC
XYZ

問題17

$ while read L; do echo $L; done < /etc/passwd > ~/a

問題18

zshだけど

$ IFS=:;declare -A A=(); while read -A a; do b=${a[7]};c=${A[$b]:-0}; A[$b]=$(($c+1)); done < ~/a; for k in ${(k)A}; do echo $k: ${A[$k]}; done
/bin/false: 2
/usr/sbin/nologin: 26
/bin/bash: 1
/bin/sync: 1
/bin/zsh: 1

問題19

$ NUM=$(<./qdata/19/cardno); for L in {,,,,,,,}; do NUM=${NUM/[0-9]/x}; done; echo $NUM

zshだと以下みたいなこともできるけど、patternが使えないので長くなるっすね

$ NUM=$(<./qdata/19/cardno); echo $NUM:s/1/x/:s/2/x/:s/3/x/:s/4/x/:s/5/x/:s/6/x/:s/7/x/:s/8/x

問題20

zshだと

$ (cd /usr; for i (*) echo $i)
bin
config
games
include
lib
lib32
lib64
libexec
libx32
local
sbin
share
src

シェル芸160ノック3

9月末ごろに発売されたシェル芸本。手を付けられていなかったのですがようやく落ち着いた感があるので少しずつ解答して行こうと思います。サクッと行きます。

gihyo.jp

前回はこちら

xztaityozx.hatenablog.com

問題12

#!/bin/bash

ARG="${1:-$(cat)}"

echo $((ARG*2))

問題13

$ [[ -e "unfile" ]] || touch unfile && cat unfile

問題14

$ seq 100 | awk '{print "echo 羊が"NR"匹&&sleep 1s"}' | bash

問題15

$ echo I am a perfect human | while read A; do echo "${A^^}"; done
I AM A PERFECT HUMAN

$ echo pen-pineapple-apple-pen | tr - \   | fmt -1  | while read L; do echo ${L^}; done | paste -sd -
Pen-Pineapple-Apple-Pen

zshだと

$ echo I am a perfect human | while read A; do echo $A:u; done
$ echo pen-pineapple-apple-pen | while read A; do echo "${(C)A}"; done

シェル芸160ノック2

9月末ごろに発売されたシェル芸本。手を付けられていなかったのですがようやく落ち着いた感があるので少しずつ解答して行こうと思います。サクッと行きます。

前回はここ

gihyo.jp

問題6

$ echo {{{{_,}_,}_,}_,}'*' | fmt -1 | tr _ ' '
    *
   *
  *
 *
*

問題7

$ cat qdata/7/kakeibo.txt | ocs  "BEGIN{var s=0M;}i(F[1])>=20191000{s+=(F[2][0]=='*' ? 1.08M : 1.10M)*decimal.Parse(F[3])}i(F[1])<20191000{s+=1.08M*decimal.Parse(F[3])}END{println((int)s)}"
53612

github.com

awkでいいな…

問題8

$ cat qdata/8/access.log | teip -og "\[.+\]" -- awk -F: '{print $0, $2>=12 ? "午後" : "午前"}' | sel -- -1 | sort | uniq -c | sort -rn
      3 午後
      2 午前

問題9

$ dateutils.dseq --format "%d/%b/%Y %H:" 2016-12-24T21:00:00 1h 2016-12-25T03:00:00 | grep -f- ./qdata/9/log_range.log
192.168.77.248 - - [24/Dec/2016 21:12:20] "GET / HTTP/1.0" 200 4294
192.168.152.143 - - [24/Dec/2016 22:06:19] "GET / HTTP/1.0" 200 7255
192.168.6.132 - - [24/Dec/2016 23:00:42] "GET / HTTP/1.0" 200 4298
192.168.222.3 - - [25/Dec/2016 00:03:23] "GET / HTTP/1.0" 200 8547
192.168.101.95 - - [25/Dec/2016 01:01:40] "GET / HTTP/1.0" 200 8488
192.168.141.18 - - [25/Dec/2016 02:15:52] "GET / HTTP/1.0" 200 4533
192.168.110.169 - - [25/Dec/2016 03:06:54] "GET / HTTP/1.0" 200 3461

dseqって時間を刻みに指定できたんだなあ

問題10

$ cat qdata/10/headings.md | sd '## (.+)' '$1\n---' | sd '# (.+)' '$1\n==='
AAA
===

これはAAAです

BBB
===

これはBBBです。
楽しいですね。

CCC
---

これはCCCCです

DDD
---

これはDDDです

問題11

$ cat qdata/11/gijiroku.txt | sed -z 's/すず\n/鈴木:/g;s/さと\n/佐藤:/g;s/やま\n/山田:/g'
鈴木:あばばあばば

佐藤:あばばばばばばば!

山田:びっくりするほどユートピア!びっくりするほどユートピア!

鈴木:うひょひょひょwwwwwやまwwやまwww

佐藤:ひょおお?ひょおお???

鈴木:それでは会議を終わります

高次元の会話

シェル芸160ノック1

9月末ごろに発売されたシェル芸本。手を付けられていなかったのですがようやく落ち着いた感があるので少しずつ解答していこうと思います。特に解説とかも書かずにサクッと行きます

gihyo.jp

問題1

$ awk '$NF=="exe"' FS=\. qdata/1/files.txt 

問題2

$ ls qdata/2/img/*.png | rargs -p "(.+).png" -j5 convert {} {1}.jpg

github.com

問題3

$ seq 1e6 | awk '{printf "%d %07d\n", $1,$1}' | xargs -n2 mv

一生終わらなかった…

問題4

$ rg '^10$' ./ -l | xargs rm

github.com

問題5

$ cat qdata/5/ntp.conf | awk '$1=="pool"&&$0=$2'

第56回シェル芸勉強会に参加しました

参加しました!当日のYouTube Liveはこちら

Q1

日本語を入力せずに、「月月火水木金金」と出力する問題。元ネタ知らなくてジェネレーションギャップ。

$ echo 2021-12-0{6,6,7,8,9,10,10}| fmt -1 | xargs -I@ date --date @ +%a | paste -sd ''
月月火水木金金

固定の日付をdateに渡して曜日だけを取り出し連結する感じですね。

Q2

echo 今楽日しのみ仕で事すはか、。から初めて、今日の仕事は、楽しみですか。に並び変える問題。そういえばこんなのあったな…

$ echo 今楽日しのみ仕で事すはか、。 | grep -o .. | awk '{a=a$1;b=b$2}END{print a,b}' FS= OFS=
今日の仕事は、楽しみですか。

並び変える前の文字列に注目すると、奇数番目を取り出したあと、偶数番目を順番に取り出せば、目的の文字列が得られることがわかりますね。というわけで、grep -o ..で二列に分割したあと、awka,bで成形して出力しました。

selを使うと以下のように書けます。ワォ!便利!

$ echo 今楽日しのみ仕で事すはか、。 | sel -D '' -d '' 1::2 2::2

Q3

ANSIエスケープで色がついた文字列から色を外す問題。わりとやりたくなることあるっすよねこれ。

$ cat */*56/red.txt | col | sed -E 's/(01\;31)?mK//g'
allergy's
bluejay
persevering
furtiveness's
remedied
hyaena's
summoner's
[Kin[m[Kjure[01;31m[Kpu[m[
injure
canons
polyphony
partridge
haste
slugs
wrangling
lulls
beta
fetus's
[01;31m[Kon[m[Ksaller[01;31m[
Visigoth's
purpose

xxdをに渡してから、該当箇所を削っていくのかな?と思っていたんですが、Twittercolというのがあるのを見つけたのでそれを試してみました。これを渡すと

aller01;31mKgymK's
bluej01;31mKaymK
per01;31mKsemKvering
furtiven01;31mKesmKs's
reme01;31mKdimKed
hyae01;31mKnamK's
sum01;31mKmomKner's
[Kin[m[Kjure[01;31m[Kpu[m[
01;31mKinmKjure
can01;31mKonmKs
01;31mKpomKlyphony
partr01;31mKidmKge
01;31mKhamKste
slu01;31mKgsmK
wra01;31mKngmKli01;31mKngmK
lu01;31mKllmKs
be01;31mKtamK
fetus01;31mK'smK
[01;31m[Kon[m[Ksaller[01;31m[
Vis01;31mKigmKoth's
01;31mKpumKrpose

こんな感じになります。あとは要らないところをsedで削ればいいですね。red.ans.txtに答えがあるのでdiff取ってみます

$ cat */*56/red.txt | col | sed -E 's/(01\;31)?mK//g' | diff - */*56/red.ans.txt
$ echo $?
0

大丈夫そうですね。man colを読んでたら改行をいい感じにするツールみたいなことが書いてたんですけどわからん

Q4

端末に絵を描く問題。うむ。

$ R="\e[41m \e[49m" B="\e[44m \e[49m" C="\e[46m \e[49m" Y="\e[43m \e[49m" W=" ";echo -e "$R$R\n$W$R$R$W$W$B$B\n$W$W$W$W$W$B$Y$Y\n$C$C$C$C$W$B$Y$Y"

f:id:xztaityozx:20211102002536p:plain

力業です。色を出す方法が分かれば地道に絵を描くだけですね。

Q5

ros_logというファイルは複数プロセスが書き込みをするログファイルです。排他制御されてないとこうなるっすよね

小問1

VALUEgrepすると見つかるかけたログの片割れを探してくださいという小問。めちょあむずそう

$ cat */*56/ros_log | awk '/INFO.*INFO|VALUE/{print $0}'  | sed 's/\[INFO\]/\n[INFO]/g' | grep -vPe "DELTAS|SWEEPS|C" | awk 'NR==19{a=$0}NR==20{print a$0}4' | grep -Pe "INFO.*VALUE"

出力のフォーマットに注目すると、先頭に[INFO]という文字列が存在することがわかります。ということは片割れがいる行にはINFOが2回出てくることが考えられます。というわけで順番にこれを絞り込んでいきます。まずはログからINFOが2回以上登場する行とVALUEが登場する行をawkで取り出します。次に[INFO]が行頭にある方があとの成形に楽なので直前に改行を入れるsedをはさみます。次はgrepで余計な行を削除します。これは見つかったものを愚直に除外しただけですね。ここまでの出力をいったん下に書きます

$ cat */*56/ros_log | awk '/INFO.*INFO|VALUE/{print $0}'  | sed 's/\[INFO\]/\n[INFO]/g' | grep -vPe "DELTAS|SWEEPS|C"| nl
     1  [ INFO] [1634194596.339889867, 13.823000000]: VALUE ITERATION START
     2  [ INFO] [1634194606.707089069, 24.183000000]: VALUE ITERATION END
     3  [ INFO] [1634194644.06
     4  [ INFO] [1634194646.869207875, 64.323000000]: VALUE ITERATION START
     5  [ INFO] [1634194658.556429903, 76.002000000]: VALUE ITERATION END
     6  [ INFO] [1634194673.985755427, 91.423000000]: VALUE ITERATION START
     7  [ INFO] [1634194676.48
     8  [ INFO] [1634194685.163231380, 102.592000000]: VALUE ITERATION END
     9  [ INFO] [1634194708.5053
    10  [ INFO] [1634194711.207208496, 128.623000000]: VALUE ITERATION START
    11  [ INFO] [1634194721.287130748, 138.696000000]: VALUE ITERATION END
    12  [ INFO] [1634194771.840389194, 189.223000000]: VALUE ITERATION START
    13  [ INFO] [163
    14  [ INFO] [1634194783.119124281, 200.494000000]: VALUE ITERATION END
    15  [ INFO] [1634194836.175661508, 253.
    16  [ INFO] [1634194838.176935414, 255.523000000]: VALUE ITERATION START
    17  [ INFO] [163419484
    18  [ INFO] [1634194849.754396571, 267.092000000]: VALUE ITERATION END
    19  [ INFO] [1634194889.4049047
    20  31, 306.723000000]: VALUE ITERATION START
    21  [ INFO] [163419489
    22  [ INFO] [1634194901.293168836, 318.602000000]: VALUE ITERATION END
    23  [ INFO] [1634194926.527612289, 343.82
    24  [ INFO] [1634194928.835154334, 346.130000000]: VALUE ITERATION START
    25  [ INFO] [1634194931.730483322, 34
    26  [ INFO] [1634194939.614970195, 356.902000000]: VALUE ITERATION END
    27  [ INFO] [163419495

(説明のためにnlで行番号を振っています) 20行目のやつが今回修復したい行ですね。そして19行目が片割れです。これを連結してやりましょう。行番号が分かっているのでもうawkで直接連結します。あとはgrepで欲しいところだけ取り出して終わりです。難しかった。

小問2

ログに含まれる二つの数字は時間とのこと。なので前後の数値を

$ ... | sel 3 4 | tr -d \[\]:, | awk 'BEGIN{a=0;b=0}{print $1-a,$2-b;a=$1;b=$2}'

差分を計算してるだけですね。果たして一致するか…。

1.63419e+09 13.823
10.3672 10.36
40.1621 40.14
11.6872 11.679
15.4293 15.421
11.1775 11.169
26.044 26.031
10.0799 10.073
50.5533 50.527
11.2787 11.271
55.0578 55.029
11.5775 11.569
51.5388 51.51
27.542 27.528
10.7798 10.772

んん…。

Q6

画像を縮小する問題。ただし4マスについて画素値が最小なものを選ぶようにすることという問題。なんか動画のエンコーディング規格を勉強しているときにこういうのやったな…

$ convert */*56/house.pgm -compress none pgm:- > o
$ cat o | awk 'NR==6,0' | awk '{for(i=1;i<=NF;i++)a[NR,i]=$i}END{for(i=1;i<=384;i+=2) {for(j=1;j<=384;j+=2) {x=a[i,j]<a[i+1,j]?a[i,j]:a[i+1,j];y=a[i,j+1]<a[i+1,j+1]?a[i,j+1]:a[i+1,j+1]; printf "%s ", x<y?x:y}; print "";}}' | cat <(echo -e "P2\n192 192\n255\n") - > result.pgm

力強いawkを書きました…。元の画像はpgmで、ヘッダー部分にP5とあり、これは画素の部分はバイナリデータなことを表すので、加工しやすいようにconvertで変換しておきます。あとは…まぁ…

解答例を見ていたら、データ列の左右でminを取ったあと、転置して同じことをすれば圧縮できるというのがあってマジで天才だなと思いました。人類は安泰ですね。

Q7

a^3+b^3=6963472309248 && a<bとなるa,bの組を見つける問題。これは時間内に解答できませんでした。そしてなんかお試しで投げたコマンドが暴走してメモリ食いつぶしててちょっと笑ってしまいました(笑えない)

全探索するとめちゃめちゃ時間がかかってしまうので、範囲を狭めたりa^3の判定をいい感じにしたりする必要があるらしいです。

というわけでこれを書きながら考えた解答が以下

$ seq 20000 | awk '6963472309248 - $1^3 > 0{print 6963472309248-$1^3}' | factor | nl -nln | sed -E 's/\s+/ /g' | awk '{delete(a);for(i=3;i<=NF;i++)a[$i]+=1;f=0;cum=1;for(x in a){f+=a[x]%3;cum*=x^(a[x]/3)};print $0,f==0?"ok":"ng",cum}' | grep ok | sel -- 1 -1 | awk '{if($1<$2){print}else{print $2,$1}}' | sort -ru
5436 18948
2421 19083
13322 16630
10200 18072

方針は解説でされたものと同じです。候補となるa^3をリストアップしたあと、factorにかけて素因数分解。その結果からa^3となりうる行かどうかをawkで計算しあとは成形して終わりですね。時間内にときたかったな…。

LT

今回もLTさせていただきました!

www.slideshare.net

ちょうど1年前のシェル芸勉強会でLTしたselというコマンドのリファクタリングを頑張ったよという話です。IO改善とか遅延評価とかなんかもうえらいこっちゃな話をしました。

github.com

今回パフォーマンスを意識したプログラミングをほぼ初めてやったので、良い勉強になりました。初期実装からかなり良くなったんですけど、selfC言語版よりはまだ遅いらしいので恐ろしいですね(C言語版を持ってないのでわからんけど)

スライドにもあるとおりとりあえずモチベとしていたラインまでは達成したのでまぁ今のところはいいかなと思っています。気が向いた時にまた改善します。

終わり

今回も楽しかったです!図形を書いてくださいという問題、冷静に考えたら???????という感じなのですが、「そうだ、\e[42mを使おう」と方針を決定できる自分が恐ろしかったです。慣れってやつかな…!

企画&開催ありがとうございました!

雑記 2021/09/03

はい

推し

どんなにストレスがかかっていても、推しがいれば大丈夫!

これは本当なんだろうか。推しの提供する最強コンテンツが間違いなく最強なのはそれはそう。僕の最推しが提供するコンテンツも僕にとっては最強。それはそうなんだが…。

ゲーム

なんかアウトプットがしたいのでゲームの進捗を書くだけの記事とかもやってみようかな…でもSS撮ったり面倒だな…

終わり

ハラヘッタ…

| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
||
|    制作・著作    |
|   ̄ ̄ ̄ ̄ ̄ ̄ ̄  |
|    xztaityozx    |
|_________|
  ∧∧   ||         
  ( ゚д゚)||           
  /    づΦ