Upgrade to Pro — share decks privately, control downloads, hide ads and more …

シェル芸のせかい / the Shellgei World

シェル芸のせかい / the Shellgei World

360e261b6fd944173cc6d09e20d78fe4?s=128

Ryoto Saito

March 09, 2020
Tweet

More Decks by Ryoto Saito

Other Decks in Programming

Transcript

  1. シェル芸のせかい Ryoto (@systemctl_ryoto) 2020/03/09 Uedalab Meetup 1

  2. こんにちは 今日はシェル芸のお話をします $ echo こんにちは $ echo すましを話おの芸ルェシは日今 | rev

    2
  3. $ w3m https://ja.wikipedia.org/wiki/シェル 芸 | grep ^シェル芸 -A 5 シェル芸[編集]

    シェル芸とは、主にUNIX系オペレーティングシステムにおいて「マ ウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間 もなく、あらゆる調査・計算・テキスト処理を CLI端末へのコマンド 入力一撃で終わらせること」(USP友の会会長・上田隆一による定 義^[9])である。この技術を持つ人物を指すシェル芸人という呼び 方も存在する^[10]。 3
  4. シェル芸モチベーション • コマンド実行を効率化する • シェルの機能を最大限利用する • やりたい動作を素早く実現する • とっさの時のサーバトラシュー力が向上する •

    GUIよりCLIの方が軽量、ソフトウェアも多い[要出典] 4
  5. シェル芸とその基礎:標準入出力(stdio) 5

  6. シェル芸を始める前に:標準入出力 • 入出力の抽象 • 標準入力(0)、標準出力(1)、標準エラー出力(2) • ファイルディスクリプタ番号は固定 • デフォルトはターミナル(tty)にバインドされている •

    リダイレクト(<, >, <<, >>, etc.)によってファイルなどへ変更可 能 シェル芸とその基礎:標準入出力 (stdio) 6
  7. $ echo terminal >$(tty) $ echo stdout >/dev/stdout terminal #

    ターミナルへ直接出力 stdout # 標準出力へ出力(=何も指定しないのと一緒) 別の画面のttyに向けて echo hello >/dev/tty?? すると…? program /dev/tty?? /dev/stdout シェル芸とその基礎:標準入出力 (stdio) 7
  8. $ echo うっしっし | cowsay # pipe “|” は前のプロセスのstdoutと後のstdinをつなげる #

    これで立派なシェル芸人 _________________ < うっしっし > ----------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || pipe stdout echo stdin cowsay シェル芸とその基礎:標準入出力 (stdio) 8
  9. シェル芸の沼にハマると • シェルでCMSを作って運用し始める https://github.com/ryuichiueda/bashcms2 • シェルでHTTPサーバを作り始める https://github.com/ryotosaito/shttpd • 少ない記号種でdateを実行するゴルフ?が始まる https://twitter.com/minyoruminyon/status/1152161173158055936

    • シェル芸をTwitterに投下できるbotを作る https://github.com/theoremoon/ShellgeiBot • VUIでシェル芸をしたくなった結果呪文詠唱を始める https://speakerdeck.com/amanoese/vuidesieruyun-woshi-xing-dekiruyounisitemita 9 シェル芸とその基礎:標準入出力 (stdio)
  10. $ echo fd1 >/dev/fd/1 $ echo alias >&1 fd1 #

    ファイルディスクリプタ1 (= stdout) に出力 alias # >&1 は >/dev/fd/1のエイリアス まとめ:標準出力の表し方 • /dev/stdout • /dev/fd/1 • >&1 シェル芸とその基礎:標準入出力 (stdio) 10
  11. $ echo stderr >/dev/stderr $ { echo error >&2; }

    2>error.txt stderr # 標準エラー出力 → ttyに出力 # “error” を標準エラーに出力 → さらに error.txt に転送 # 標準出力も標準エラーもデフォルトはttyにバインド シェル芸とその基礎:標準入出力 (stdio) 11 program /dev/tty?? /dev/stdout /dev/stderr /dev/tty?? error.txt
  12. $ man life 2>&1 | cowsay $ man life |&

    cowsay 標準エラー出力をpipeしたい場合は、 • プロセス中で標準出力にリダイレクトする • 標準エラー出力も一緒にpipeする ’|&’ を使う __________________________ < No manual entry for life > -------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || シェル芸とその基礎:標準入出力 (stdio) 12
  13. シェル芸の基礎:シェル機能 13

  14. コマンド出力をコマンド文字列として認識する Command substitution $ docker rm $(docker ps -aq) #

    dockerのコンテナを全て削除する # docker ps -aqはコンテナIDをリストする # 展開対象は標準出力(stderrはttyに垂れ流される) シェル芸の基礎:シェル機能 14
  15. $ paste <(seq 1 3) <(seq 4 6) 1 4

    2 5 3 6 # equivalent to # seq 1 3 >13.txt; seq 4 6 >46.txt; paste 13.txt 46.txt $ echo <(seq 1 4) <(seq 4 6) /dev/fd/63 /dev/fd/62 コマンド出力をファイルとして認識する Process Substitution シェル芸の基礎:シェル機能 15
  16. その他Bashの有用な機能 • /dev/tcp/host/port でネットワークリダイレクト ◦ exec 3<>/dev/tcp/localhost/80 ◦ echo -e

    "GET / HTTP/1.1\r\n\r\n" >&3 ◦ while read line <&3; do echo $line; done • command1 || command2で失敗時処理 • ((i++))などの演算や、for ((i=0;i<10;i++))の記述 • declare -n や local -n で変数の参照を得る • {a,{b,c}d}e → ae bde cde のようなブレース展開 • ENV=param commandで、command実行時のみENVを変える シェル芸の基礎:シェル機能 16
  17. 闇の魔術 :(){ :|:&; };: 絶対に実行してはいけない(cf. forkbomb) function colon() { colon

    | colon& } colon 片方 (:&) がバックグラウンドプロセスになり、killできない プロセステーブルが飽和し、端末が死亡 閑話休題 シェル芸の基礎:シェル機能 17
  18. シェル芸に関わる規範たち 18

  19. UNIX哲学 一つのことを行い、またそれをうまくやるプログラムを書け。 協調して動くプログラムを書け。 標準入出力(テキスト・ストリーム)を扱うプログラムを書け。標準入出力 は普遍的インターフェースなのだ。 https://ja.wikipedia.org/wiki/UNIX哲学 シェル芸に関わる規範たち 19

  20. POSIX • Portable Operating System Interfaces • https://pubs.opengroup.org/onlinepubs/9699919799/ • Xは?→

    UNIXからきてる • C標準ライブラリやシェル(sh)の仕様が統一されている • 基本的なコマンド(Utilities)も載っている ◦ awk, cd, chmod, ls, sed, xargs, 他たくさん • 拡張シェル(bash, etc.)は(基本的に)これを守ってる • POSIXの仕様を守っている限りどの環境でも動くはず! シェル芸に関わる規範たち 20
  21. sedとawkはPOSIX準拠 現在でも幅広くsedやawkが使われている理由の一つ (もちろんテキスト処理に特化しているというのもある) ただしGNU sed/awkなど独自拡張を行っているものもある • sed -r、sed -i、sed -y

    • awkの各種強力な関数(丸投げ) 環境依存を気にするようになったら一歩沼に沈んだ証 シェル芸に関わる規範たち 21
  22. GNU Coreutils 流石にPOSIXコマンドだけじゃ足りないことも多いので、 追加で存在を前提とされるコマンド群がある fmt, shuf, tee, seq, factorなど 一部コマンドは

    POSIX にオプション拡張したものもある Coreutilsをさらに拡張したMoreutilsもある シェル芸に関わる規範たち 22
  23. シェルでできる便利なコマンド 23

  24. $ { time sleep 1 &>/dev/null; } 2>&1 | tail

    -3 | awk '{print $2}' | xargs | tr ' ' , 0m1.052s,0m0.009s,0m0.021s # sleep 1を任意のコマンドに置き換えれば計測自動化できる # Bashのtimeコマンドの出力に依存している # for文や>>リダイレクトで複数条件計測とcsv錬成ができる シェルでできる便利なコマンド 24 $ time sleep 1 <空行> real 0m1.052s user 0m0.009s sys 0m0.021s | tail -3 | awk... 0m1.052s 0m0.009s 0m0.021s | xargs 0m1.052s 0m0.009s 0m0.021s
  25. $ $(pbpaste) | pbcopy # macos $ $(xsel -b) |

    xsel -bi # Linux (X) # Clipboardのコマンドを実行した結果をClipboardに入れる pbcopy/pbpasteは標準で入っている xselはパッケージマネージャを通してインストール可能 シェルでできる便利なコマンド 25
  26. CSI(Control Sequence Introducer) ESC(0x1b) [ のエスケープシーケンスを入力することで様々な端 末制御が可能となる 文字色・カーソル移動・文字削除・端末サイズ変更、etc. • sh

    → printf '\x1b[31mRED\x1b[m' • bash → echo -e '\x1b[31mRED\x1b[m' • zsh → echo '\x1b[31mRED\x1b[m' RED # 表示設定(m):前景色(30)が赤(1)になる=31m もっと直感的に指示したい場合はtputコマンドがある 26 シェルでできる便利なコマンド
  27. シェル芸人御用達コマンド・イディオム 27

  28. # 整形コマンドとしてのxargs $ seq 12 | xargs -n 3 1

    2 3 4 5 6 7 8 9 10 11 12 # 通常xargsは標準入力を最後尾に配置してコマンド実行する $ ls | xargs tar cvf dir.tar # が、コマンドを書かないとただの整形コマンドと化す $ echo -e "many spaces \tand\ttabs\!\!" | xargs many spaces and tabs!! シェル芸人御用達コマンド・イディオム 28
  29. # 任意箇所に埋め込むxargs $ ls | xargs -I{} echo "There is

    {} here." There is Desktop here. There is Documents here. … # I(large i)オプションによって任意の場所に埋め込める # 直後に指定した文字列を置換する # 複数箇所指定も可能 シェル芸人御用達コマンド・イディオム 29
  30. $ seq 10 | tr '\n' ' ' $ seq

    10 | tr -d '\n' 1 2 3 4 5 6 7 8 9 10 # 改行をスペースに変換する 12345678910 # 改行を消滅させる # この方法は一番最後の改行(10\n)も対象なことに注意 シェル芸人御用達コマンド・イディオム 30
  31. $ seq 10 | tee >(tac | xargs > rev.txt)

    | xargs | tr ' ' + | bc 55 # cat rev.txt -> 10 9 8 7 6 5 4 3 2 1 # teeコマンドは本来ファイルと標準出力へsplitさせる # Process Substitutionによって2つのコマンドに渡せる # 並行処理なので両方とも標準出力に流すと大変 # 環境を気にしないのならpeeコマンド(moreutils)が便利 $ seq 10 | pee "tac | xargs > rev.txt" "xargs | tr ' ' + | bc" シェル芸人御用達コマンド・イディオム 31
  32. $ echo Helloworld | grep -o . H e l

    l o w o r l d # grepは基本的にマッチした行を抜き出す # -oはマッチした箇所のみを抜き出す # . は任意の1文字なので、全文字が分割表示される シェル芸人御用達コマンド・イディオム 32
  33. $ yes 'echo $RANDOM' | head -3 | bash 28995

    29287 23092 # コマンドを自力で生成してからpipe先のbashに投げて実行 # 複雑なコマンドを生成するもよし、 # ランダム要素のあるコマンドを何回も実行するときも便利 # seqをパイプすればfor文より見た目がエレガント[要出典] シェル芸人御用達コマンド・イディオム 33
  34. $ shuf -ren10 {大,中,小,末,}吉 {大,}凶 # おみくじ10連打 • -r 再抽選可

    • -e 標準入力ではなく引数をシャッフル • -n10 10回出力 # Q. 本当に御用達なんですか? # A. 他に書くとこがなかった シェル芸人御用達コマンド・イディオム 34
  35. $ sudo cat /var/log/auth.log | grep "Invalid user" | cut

    -f9 -d' ' | sort | uniq -c | sort -nr | head -10 # ssh不正ログインしてこようとしたusernameを暴く # Ubuntu 18.04で動作した # sort | uniq -c | sort -nr は最頻ランキングを作るのに便利 # cut -fnum -d' ' はスペースで区切られたnum番目を取得 シェル芸人御用達コマンド・イディオム 35
  36. 難読化 36

  37. $ $(echo d)$’\x61’$(echo dGUK | base64 -d) Mon Mar 9

    09:46:30 JST 2020 # それぞれ展開すると “date” になる # シェルは展開できるものを全て展開した後に解釈する • echo d → d • $'\x61' → a • echo dGUK | base64 -d → te 難読化 37
  38. 難読化テクニックたち echo $[] → 0 ($[]は算術演算、何もないと0) echo ${##} → 1

    ($#:引数の数=0、${#var}:文字列長) $(: shutdown -h now) (一瞬ひりつかせるが何もしない) /???/???/???1??? (/usr/bin/sha1sumを呼ぶ、環境依存) cut -c n (標準入力のn文字目を取り出す。切り貼りする) 難読化 38
  39. ところで Connpassページのシェル芸、Bashで実行できます $ pbpaste | bash ShellGei!! 難読化 39

  40. どういうこと $ pbpaste | bash -x でデバッグできる ___=$(.&>/???/??/${##}); ___に .

    &>/dev/fd/1 の出力を代入する .コマンドがエラーを返すので、それをfd1にリダイレクト -bash: .: ファイル名が引数として必要です .: 使用法: . filename [arguments] __=$? __に$?(直前コマンドの終了ステータス=2)を代入 難読化 40
  41. つづき ! ___=${___##*.} ___に、___の最後の.以降の文字列を代入 -bash: .: ファイル名が引数として必要です .: 使用法: .

    filename [arguments] 言語環境に依存しない部分を抽出(このメッセージ自体はBashの builtinなので、Bashで実行している限り変わらない) 難読化 41
  42. つづき ____=$(${___:$(($__$#-$?)):$?}${___:$__*$__:$?}${___:$ (($__$#-$__)):$?} -${___:$(($__#$?$?$#$?)):$?}&>/???/??/$?) 先ほどのコマンドで!をつけたので、$?が反転して1になる $#は0、これらで$___=' filename[arguments]'を切り貼り ____=$(set -g &>/dev/fd/1)

    bash: 1 行: set: -g: 無効なオプションです set: 使用法: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...] 難読化 42
  43. つづき これらを繰り返して最終的に ___=(eval $(echo {a..\u7a})) ___=(a b c d e

    … x y z) # ___はarrayになる を取得 配列インデックスをいじって任意コマンドが実行できる 難読化 43
  44. さいごに 44

  45. シェル芸勉強会 • 2ヶ月に1回新宿で開催される勉強会 • 界隈がfreakyで面白い(沼にハマった人たちを参考) • シェルのワンライナーという制約下で8問解く 例えば: 日経のページから日経平均株価の日次データをダウンロードし て、毎月の終値の最高値と最安値を出力してください。

    https://b.ueda.tech/?post=20191228_shellgei_45#q2 勉強会リンク(https://usptomo.doorkeeper.jp/) 45 さいごに