今さらだけど覚えておいた方が良いUnix, Shellコマンド


TerminalやiTermなどのCLIツールでコマンドを叩いて作業をすることが多いですが、その中で「これ知っておいた方が良かったなー」というコマンドは幾つかあります。

プログラミングを始めて0~3年ぐらい、たまにCLIツールで作業するけど、これからどんどんその機会が増えるかもしれないという方を対象読者として想定しています。

使用頻度の高いコマンド

grep

「指定したファイルの中身の文字列を検索する」

$ grep [オプション] [検索対象文字列] [検索対象ファイル/ディレクトリ]
$ grep -rn "test" ./
オプション 詳細
-r ディレクトリを再帰的に検索する
-n 行番号を表示する
-v マッチしない行を表示する
-i 大文字と小文字を区別しない
-(数字) マッチした行の前後数字分の行も出力する

よく使うのは、grep -rn [文字列] ./です。どこのファイルの何行目に記述されているか明確になるからです。
またgrep -rn [文字列1] ./ | grep -v [文字列2]などして、「文字列1が含まれる行の中で、文字列2がない行」を探すといったこともしたりします。

xargs

「標準入力からきたコマンドラインを引数に渡す」

$ [コマンド] | xargs [コマンド]
$ seq 1 10 | xargs echo
1
2
3
...
9
10
オプション 詳細
-t 実際に実行するコマンドを表示してくれる
-n (数字) 数字の個数分ずつxargsの引数のコマンドに渡す
-Ixxx xargsの引数のコマンドに対してxxxでその値を渡す(xxxは文字列ならOK)

-nオプションは、説明だとわかりづらいですが、上記のコマンドの例を使うすると、

$ seq 1 10 | xargs -n 2 echo
1 2
3 4
5 6
7 8
9 10

といった感じになります。

-I オプションの使いどころは、例えば、10個のディレクトリを「(数字)_dir」みたいなのをいっぺんに作りたいとすると、

$ seq 1 10 | xargs -Ixxx mkdir xxx_dir
$ ls -1
10_test
1_test
2_test
3_test
4_test
5_test
6_test
7_test
8_test
9_test

のようにして使います。「xxx」だと多少わかりづらくなってしまうと思うので、「{}」とかのが文字列との区別がしやすくなるかもしれません。

sed

「行ごとに文字列を置換する」

$ sed [オプション] [変換プログラム] [対象ファイル]
$ sed 's/test/text/g' test.txt

sedコマンドは使いそうなオプションがないので、変換プログラムを記述しておきます。

sed 's/hoge//'                <- hogeの部分を削除する
sed '/a/,/c/d'                <- dつけると対象行を削除する
sed 's/hoge/foo/g'            <- gつけると入力行の対象のやつ全部置換する
sed 's/.*/foo/'               <- 全部の行を置換する
sed 's/.../foo/'              <- なんでもいいから三文字分置換する
sed 's/^/foo/'                <- 行頭に追加
sed 's/\$/foo/'               <- 行末に追加
sed '5/hoge/foo/'             <- 5行目だけ置換する
sed '5,10s/hoge/foo/'         <- 5行目から10行目まで置換する
sed '5,$s/hoge/foo/'          <- 5行目から最終行まで置換する
sed 's/\(...\)\(....\)/\1\2/' <- ()で囲まれた部分を\1\2に代入して出力してる
sed 's/\/_/'                  <- バックスラッシュでエスケープ文字
sed 's@/@_@'                  <- 一個上のやつと一緒の処理
sed '/a/,/c/s/./>>>/g'        <- aからcまでの行を指定して置換する

よく使うのは、「特定の文字列を含むファイルがとても多いときに、一気に置換する」といったことに使用したりします。

$ find . -type f | xargs sed -i 's/hoge/yeah/g

find

「ファイルを探す」

$ find [検索対象/ディレクトリ] [オプション] [検索対象ファイル名]
$ find ./ -name test.txt
オプション 詳細
-name オプションの後ろのファイル(ディレクトリ)名を対象にする
-type ファイルタイプを区別する(d:ディレクトリ,f:ファイル,l:シンボリックリンク
-iname 大文字と小文字を区別しない

アプリケーション内や/etcなどの中からファイル名を探すときに使ったりしますが、grepなどと組み合わせて使用することもよくあります。

例えば、特定のファイルから特定の文字列を探すといったことをしたりします。

$ find -name "hoge" -type f | xargs grep "foo"

もちろんxargsを使ったのは、文字列としてgrepの引数に渡すのではなく、「ファイル名である」というのを認識させるためです。

sort

「ソートする」

$ sort [オプション] [対象ファイル]
$ sort foo.txt
オプション 詳細
-n 数字は数字としてソートする
-k 引数でした列でソートする
-r 逆順に表示する

sortコマンドの引数に対象ファイルと書きましたが、よく使うのは「パイプでソートするものを渡す」ということをします。
具体的には、ls -la | sortといった形でソートします。アルファベット順にも数字順にも並べることができるので、ログなどを見やすくしてくれたりします。

uniq

「重複行を削除する(ソート済みの行が対象)」

オプション 詳細
-c 重複した数を表示する
-d 重複した行のみを表示する
-i 大文字小文字を区別しない

uniqコマンドは、sortされてものでないと扱うことができません。なので基本的には、ls -la | sort | uniqみたいな使い方をするかと思います。

tail

「ファイルの末尾を表示する(デフォルトで10行)」

$ tail [行数] [オプション] 対象ファイル
$ tail -5 log/production.log
オプション 詳細
-f 表示しても終了せず、追加分を随時更新していく

logファイルなどにtail -f ...として使ったりします。

使用頻度低いけど知っておいて損がないコマンド

seq

「連続して数字を出力する」

$ seq [最初の数字] [最後の数字]
$ seq 1 10
1
2
3
...
10
オプション 詳細
-f フォーマットを指定する
$ seq 1 10
1
2
3
...
10
$ seq 3 5 30
3
8
13
18
...
28
$ seq -f "%g_test" 1 3
1_test
2_test
3_test

一つ目のコマンドは、「1~10までを+1しながら出力する」ですが、二つ目は「3から+5しながら30までの数字を出力する」といったコマンドです。
三つ目はフォーマット指定の例です。

pgrep

「プロセス名や属性を指定して、プロセスのIDを表示する」

$ pgrep [オプション] [プロセス名]
$ pgrep -f unicorn
オプション 詳細
-f パターンのマッチ対象を行全体にする
-l プロセス名も表示する
-i 大文字小文字を区別しない
$ pgrep -f unicorn

プロセスからプロセス名を探す時、ps aux | grep unicornなどやりますが、上のように短縮して実行できます。

pkill

「プロセス名や属性を指定して、プロセスのIDを殺す」

$ pkill [オプション] [プロセス名]
$ pkill -f unicorn
オプション 詳細
-f パターンのマッチ対象を行全体にする

これはわざわざps aux | grep unicornなどしてプロセスIDを探してkillコマンドを実行するという手順を踏まずに、一致したプロセスを殺します。便利ですが、注意が必要です。

lsof

「プロセスがオープンしているファイルを表示する」

$ lsof [オプション] []
$ lsof -c vagrant
オプション 詳細
-i ポートを指定する
-c コマンドを指定する

ps コマンドもプロセスを表示してくれますが、 ps コマンドは「実行しているコマンド」を表示してくれるのに対し、 lsof コマンドは、「開いているファイル」を表示してくれます。

$ lsof -c vagrant
vagrant 71370 [ユーザー名]  cwd    DIR    1,4        238 3187321 /path/to/
vagrant 71370 [ユーザー名]  txt    REG    1,4    2174112 3178860 /opt/vagrant/bin/vagrant
vagrant 71370 [ユーザー名]  txt    REG    1,4     639664  768714 /usr/lib/dyld
vagrant 71370 [ユーザー名]    0u   CHR   16,1 0t50497761    2221 /dev/ttys001
vagrant 71370 [ユーザー名]    1u   CHR   16,1 0t50497761    2221 /dev/ttys001
vagrant 71370 [ユーザー名]    2u   CHR   16,1 0t50497761    2221 /dev/ttys001
$ ps aux | grep vagrant
[ユーザー名]       71322   4.1 12.8  3622220 1076820   ??  S    火10PM  36:15.04 /Applications/VirtualBox.app/Contents/MacOS/VBoxHeadless --comment nix_vagrant_default_1477387253017_85200 --startvm 2ab60830-2696-4ef2-853c-65b400cbc2d8 --vrde config
[ユーザー名]       71371   0.0  0.0  2464476    392 s001  S+   火10PM   0:07.28 ssh [email protected] -p 2222 -o Compression=yes -o DSAAuthentication=yes -o LogLevel=FATAL -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /path/to/.vagrant/machines/default/virtualbox/private_key
[ユーザー名]       71370   0.0  0.0 556597992    228 s001  S+   火10PM   0:00.05 vagrant ssh

diff

「二つのファイルの差分を表示する」

$ diff [ファイル1] [ファイル2]
$ diff hoge.txt foo.txt
オプション 詳細
-u unified形式のフォーマットで出力する

unified形式とは、 git diffコマンドを使用したことがある人ならわかると思いますが、「-」「+」といった形で、どの行が削除されどの行が追加されたかを表示してくれます。

おまけ

絵文字を出力する

$ echo -e '\U1F37B \U1F389'
$ 🍻 🎉

絵文字はUnicode文字なので、echoコマンドで出力することができます。 -e は、エスケープコードを扱うためのオプションです。
他の絵文字も出力することができますので、ぜひお試しください。以下のリンクに絵文字の一覧がございます。

slを出発させる

sl と打つと機関車が走るというコマンドです。
Homebrewをお使いの方は、brew install slでコマンドをインストールすることができます。
また apt-getyum でもインストール可能です。

$ sl
実行するまでのお楽しみです!

ちなみに man sl と打つと、slコマンドの説明がありますが、そこには、、、
「sl - cure your bad habit of mistyping」
ls コマンドのタイプミスが多かったようでそれの防止に作られたようです。細かいことは以下のリンクに記載されていますので、気になる方はご覧ください。

補足

紹介しきれなかったコマンド(特にawk)は多数あり、随時追加していこうと思ってます。
また、MacかLinuxでコマンドの実行時に挙動が多少違う場合があります(BSD系UnixかGNU系Unixの違いです)。