はじめに
いきなりですが問題です。「👇ここ」は一体何の値でしょう?
$ ps -u | grep bash 👇 ここ
koichi 2925430 0.0 0.0 10804 6040 pts/7 Ss 20:31 0:02 -bash
koichi 2970810 0.0 0.0 8824 5568 pts/23 Ss 20:35 0:00 -bash
koichi 3061064 0.0 0.0 8688 4204 pts/22 Ss 21:11 0:00 -bash
koichi 3309961 0.0 0.0 8820 5832 pts/0 Ss 22:03 0:00 -bash
というような問題を解くのが嫌になったので、hdr
コマンドを作りました。コマンドの前に hdr
と書くだけでヘッダ行を残すことができます。
$ ps -u | hdr grep bash 👇 ここ
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
koichi 2925430 0.0 0.0 10804 6040 pts/7 Ss 20:31 0:02 -bash
koichi 2970810 0.0 0.0 8824 5568 pts/23 Ss 20:35 0:00 -bash
koichi 3061064 0.0 0.0 8688 4204 pts/22 Ss 21:11 0:00 -bash
koichi 3309961 0.0 0.0 8820 5832 pts/0 Ss 22:03 0:00 -bash
それ awk でできるよ?
面倒なので書きたくありません。hdr
コマンドは対話シェル用です。シェルスクリプトの中に書く場合は以下の方法を使いましょう。
$ ps -u | awk 'NR==1 || /bash/'
上記のコードは awk を使う前提となってしまいますが、hdr
コマンドは任意のコマンドを呼び出せるので rg
や ag
などと組み合わせて使うことも出来ます。また sort
コマンドと組み合わせることもできます。
$ ps -u | hdr grep bash | hdr sort -k 5,5n
hdr コマンドは組み合わせて使えるコマンドを作るという Unix 哲学的な考え方のコマンドです。
hdr コマンドの使い方
使用するときは以下のコードを .bashrc
なり .zshrc
なりにコピペするか、.
(source
) コマンドで読み込んでください。
hdr() {
( IFS= read -r REPLY && printf '%s\n' "$REPLY" )
"$@"
}
alias hdr="hdr "
( ... )
を使っているのは REPLY
変数をローカル化するためです。local
コマンドでローカル変数にしていないのは、local
非対応の POSIX シェルにも対応するためです。REPLY
変数は bash などでは省略可能ですが、省略できない POSIX シェルもあります。head -n 1
は1行ではなくある程度のサイズを読み込むので動作しません。alias
については後述します。
ヘッダが二行以上の場合にも対応したいとかヘルプを表示したいとか高機能なものが欲しい人はこちらをどうぞ
hdr() {
case ${1:-} in
-h | --help) set -- ;;
--) shift && set -- 1 "$@" ;;
*[!0-9]*) set -- 1 "$@" ;;
esac
if [ $# -eq 0 ]; then
echo "Usage: hdr [num | --] [command [args...]]"
else
(
while [ "$1" -gt 0 ] && IFS= read -r REPLY; do
set -- $(($1 - 1))
printf '%s\n' "$REPLY"
done
)
shift
"$@"
fi
}
alias hdr="hdr "
なんでシェル関数にしたの?
普段私は特別な理由がない限り、ツールは単独のシェルスクリプトにするのですが、今回はそれでは不便だったので rc ファイルに定義するシェル関数にしました。理由はエイリアスです。
grep
コマンドって普通色が付きますよね? 人によっては付かないかもしれませんが。色がつく理由は次のようなエイリアスが設定されているからです。
alias grep='grep --color=auto'
しかし、ここで hdr
を単独のシェルスクリプトにしてしまうと、このエイリアスは展開されません。
👇ここは hdr コマンドの引数なのでエイリアスが展開されない
hdr grep bash
仕方ないので hdr
をエイリアスにする必要があります。なぜ hdr
をエイリアスにするという話につながるんだ?と思うかもしれませんが、エイリアスのちょっとマイナーな機能を利用しています。
alias hdr="hdr "
👆 末尾のスペースが重要
エイリアスの設定で末尾にスペースがあると
👇 hdr のエイリアスが展開されたあとに・・・
hdr grep bash
👆 hdr の次の単語もエイリアス展開の対象になる
という動作をします。これにより hdr
コマンドを使っても grep
コマンドは以前と同様に動作を行ってくれます。この機能は前から知ってはいたのですが、なにげに初めてまともな使い方をした気がします。
実際には alias
部分だけを rc ファイルに入れれば hdr
コマンドは単独のシェルスクリプトにできるのですが、この程度なら分けるよりも一つのまとめたほうが良いかなと思いました。
さいごに
前々から不便に感じてイライラしていたのですが、さっさと作っておくべきでしたね。記事を書く時間のほうが長かったです。自動化するためにシェルスクリプトがあるというのに、作る手間を惜しんで毎回手作業を行うのはシェルの正しい使い方ではありません。