ひびのログ

日々ではないけどログを出力していくブログ

シェル芸ロードマップ

シェル芸(シェルコマンド)の使い方を覚えるための課題を作ってみた。 内容は「自分はこんな感じで学んでいったような気がする」という完全なる主観。

課題

  1. ファイル一覧を出す
    • ls とよく使うオプション a, l, t, 1
  2. ls のヘルプを見る
    • ls --help, man ls
  3. ls の実体がどこにあるのか調べる
    • type
  4. ファイル一覧を絞り込み
    • ls, grep
  5. カレントディレクトリ以下のファイルを列挙
    • find
  6. カレントディレクトリにファイルがいくつあるか数える
    • ls, grep, wc -l
  7. カレントディレクトリのファイルを、拡張子なしで一覧化する
    • ls, sed -e 's/\.[^\.]*$//g'
  8. カレントディレクトリの 2 つ下のディレクトリを一覧化する
    • find, awk -F"/" '{ print $3 }', sort, uniq
  9. example.com の body タグの内容を出力する
    • curl, sed -n -e 'p'
  10. カレントディレクトリに aaa ディレクトリを作成する
    • mkdir
  11. aaa ディレクトリに test.txt ファイルを作成する
    • touch
  12. aaa/test.txtHello World! と書き込む
    • echo, >>
  13. aaa/test.txt の中身をクリップボードにコピーする
    • cat, pbcopy(Mac の場合)
  14. カレントディレクトリのファイル一覧と、aaa ディレクトリのファイル一覧の差分を見る
    • ls, diff, <(〜〜)(Process Substitution)
  15. カレントディレクトリ以下のファイルにおいて、Hello という文字列がある場合はその行を、ない場合はファイルパスを表示する
    • find, while read -r line; do 〜〜〜; done, if grep, echo
  16. aaa ディレクトリを削除する
    • rm -r aaa
  17. 履歴を、最後から数えて 3 〜 5 行目だけ出力する
    • history (, tail), head
  18. 一秒ごとに現在時刻を表示する
    • while :; do 〜〜; done, TZ='Asia/Tokyo' date, sleep

シェルが行文字列志向だということが分かれば、何ができるのか大まかにわかるようになるはず。 こちらの記事がわかりやすい。

qiita.com

これでやりたいことのイメージがつきやすくなる(といいなぁ)。 あとはググる。

補足

正規表現を使う系のコマンドがうまくいかなかったら GNU 系のコマンドをインストールしてあげるといい。 多少挙動やオプションが違ったりするが、基本的には問題ないはず。

参考:https://kawaken.dev/posts/20200811_install-basic-gnu-commands/

この後は以下を学ぶといいかも

  • PATH, 変数, 環境変数
  • パイプ, エスケープ(特殊文字), 終了ステータス, サブシェル, $()(Command Substitution)
  • cut, paste, test, xargs, pushd, popd, seq, tac, rev, tee

実用的なシェル芸パーツ

実例なんでそのままは使えない可能性がある。 他のコマンドやオプションを使えば、もっときれいにできることがあるかも。

  • cat
    • ファイルの中身に対してなんかしたいときはまずこれ
  • git log --oneline | awk '{ print $1 }'
  • git status | grep modified | sed -r -e 's/^.*: +//g'
    • | while read -r line; do echo "$line"; done
  • | sort | uniq
  • | while read -r line; do 〜〜〜; done
  • xx && yy || zz
  • while :; do sleep 1; done

ほか他に知っておくと便利なもの

  • bash のショートカットキー(tab 補完, ctrl + a|e, ctrl + r 等)
  • zsh の機能(プロンプトカスタマイズ, ブレース展開, Glob 等)
  • bash, zsh のエイリアス(alias コマンド)
  • vim, less
    • ファイルの中身を見るだけのときは less を使う
      • j, k, G, F, B, /, &, Shift + F あたり
  • よく使うコマンド(Git, docker 等)のサブコマンド・オプション・仕様
  • 正規表現
  • シェルスクリプトの書き方
    • shebang, set -eu, 関数
  • sed
  • awk

参考にするとよさそうなやつ

課題の答え

# ファイル一覧を出す
ls
ls -al
ls -alt # 更新日時降順だった気がする、ログ見るときに使ってや
ls -1 # シェル芸するならこれがいい

# ls のヘルプを見る
## コマンドのヘルプを見るのは --help オプションや man コマンド
ls --help
man ls

# ls の実体がどこにあるのか調べる
type ls # 普段はこれがおすすめ
where ls # PATH に存在するものがすべて表示される

# ファイル一覧を絞り込み
ls -1 | grep 'test'

# カレントディレクトリ以下のファイルを列挙
find . -type f

# カレントディレクトリにファイルがいくつあるか数える
## grep 部分はもっといいやり方がある気がする
ls -a1 | grep -v '^\.+$' | wc -l

# カレントディレクトリのファイルを、拡張子なしで一覧化する
ls -1 | sed -e 's/\.[^\.]*$//g'

# カレントディレクトリの 2 つ下のディレクトリを一覧化する
find . -type d | awk -F"/" '{ print $3 }' | sort | uniq

# example.com の body タグの内容を出力する
curl https://example.com | sed -n -e '/<body>/,/<\/body>/ p'

# カレントディレクトリに `aaa` ディレクトリを作成する
mkdir aaa

# `aaa` ディレクトリに `test.txt` ファイルを作成する
touch aaa/test.txt

# `aaa/test.txt` に `Hello World!` と書き込む
echo "Hello World!" >>aaa/test.txt

# `aaa/test.txt` の中身をクリップボードにコピーする
cat aaa/test.txt | pbcopy

# カレントディレクトリのファイル一覧と、`aaa` ディレクトリのファイル一覧の差分を見る
diff <(ls -1) <(ls -1 aaa)

# カレントディレクトリ以下のファイルにおいて、`Hello` という文字列がある場合はその行を、ない場合はファイルパスを表示する
find . -type f | while read -r line; do grep -q Hello "$line" && grep Hello "$line" || echo "$line"; done
## 読みやすいのはこっちかも
find . -type f | while read -r line; do if grep -q Hello "$line"; then grep Hello "$line"; else echo "$line"; fi; done

# aaa ディレクトリを削除する
rm -r aaa

# 履歴を、最後から数えて 3 〜 5 行目だけ出力する
history | tail -n 5 | head -n 3

# 一秒ごとに現在時刻を表示する
while :; do TZ='Asia/Tokyo' date; sleep 1; done