社内でシェルスクリプトの活用が増えるといいなー、と思って、とっかかりになるようなパズル的なものを考えてみた。 シェルスクリプトに興味をもってもらうことが目的なので、いわゆる「シェル芸」のような結構手応えがあるものではなく、一部を除いてはごく簡単なものになっていると思う。
sed コマンドのバージョン
macOS に GNU sed をインストールして使っている。
$ sed --version sed (GNU sed) 4.8
sed コマンドでいろんなコマンドを再発明する
cat
cat コマンドの再発明、そして他のコマンドの再発明には、次のファイルを入力として使う。
$ cat numbers.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
sed コマンドは式を与えられない場合、入力をそのまま出力するので、それを利用する。
$ sed '' numbers.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
grep
次のようにすると grep コマンドを再発明できる。
-n
オプションを指定し、出力を抑制する- 出力したい行 (アドレス) を正規表現で指定し、マッチしたら
p
コマンドで出力する
$ grep 3 numbers.txt 1 2 3 13 14 15 $ sed -n /3/p numbers.txt 1 2 3 13 14 15
tr
次のようにすると tr コマンドを再発明できる。
y
コマンドを使って文字列内の文字を変換する
$ tr [123] [abc] < numbers.txt a b c 4 5 6 7 8 9 a0 aa ab ac a4 a5 a6 a7 a8 $ sed 'y/123/abc/' numbers.txt a b c 4 5 6 7 8 9 a0 aa ab ac a4 a5 a6 a7 a8
wc
次のようにすると wc -l
コマンドを再発明できる。
-n
オプションを指定し、出力を抑制する- 入力の最終行をマッチさせて
=
コマンドを実行し、マッチした行つまり最終行の行番号を出力する
$ wc -l numbers.txt 6 numbers.txt $ sed -n '$=' numbers.txt 6
head
次のようにすると head
コマンドを再発明できる。
- 表示したい最終行 (入力全体での2行目) をマッチさせて
q
コマンドを実行し、そこでスクリプトを終了する
$ head -n 2 numbers.txt 1 2 3 4 5 6 $ sed '2q' numbers.txt 1 2 3 4 5 6
別解。
-n
オプションを指定し、出力を抑制する- 表示したい最初の行から最終行までをマッチさせて、
p
コマンドで出力する
$ sed -n '1,2p' numbers.txt 1 2 3 4 5 6
tail
次のようにすると tail
コマンドを再発明できる *1
ここでは、ファイルの末尾2行を表示させている。
:a
にてラベルを定義する。あとでジャンプのターゲットとして使う$q;N;3,$D;ba
: この部分には以下の4つのコマンドが含まれている$q
: 直前に読み込んだ行が入力の最終行である場合、それまでの行を出力してq
コマンドでスクリプトを終了する。 これにより、最後の2行まで読み込んだ後に出力されるようになる。N
: 次の行を読み込んでパターンスペースに追加する。 これにより、複数の行をパターンスペースに保持させ、最終的には最後の2行がパターンスペースに格納される。3,$D
: パターンスペース内の行が3行以上になった場合、最も古い行 (つまり先頭の行) を削除する。 さらにD
コマンドの副作用として新しい入力行を読み込み、スクリプトが最初から実行される。 これにより、最後の2行だけがパターンスペースに保持されるようになる。ba
:b
コマンド (分岐コマンド) を実行して定義済みのラベルa
にジャンプする。 これにより、スクリプトが最初から繰り返されるようになる。
$ tail -n 2 numbers.txt 13 14 15 16 17 18 $ sed ':a;$q;N;3,$D;ba' numbers.txt 13 14 15 16 17 18
以上。
*1:パッと思いつかなくて、コマンドのリファレンスを調べたり ChatGPT に相談しながらやってみた