個人的によく使ったShellコマンドを備忘録としてまとめておきます.
※ zshで動かしているため,bashだと若干動かなかったりする🙇♂️
合計を求める
合計を求める時は,awkを利用しています.
awkコマンドは,最高に良くできるコマンドなので多用しまくりです.
❯❯❯ echo "1\n2\n3" | awk '{a += $1} END {print a}'
6
❯❯❯ echo "1 2 3" | awk '{for (i = 1; i <= NF; i++) a += $i} END {print a}'
6
awk
コマンドについて少し解説すると,awk
は渡ってきた文字列を空白区切りで分割しawk
内部で$1,$2...
として扱えるようにしてくれます.
だからカラムの合計を求める時には,a
という変数にひたすら$1
を足してますね.
そしてもう一つNF
というものがあると思います.
これは空白区切りで分割した配列的なやつの長さだと思ってください.
awk
は$0
が分割前の元の文字列を意味するので,$1
から初めて$NF
までfor
で回してあげています.
そしてEND
という文字の後に書いた処理は,最後に一回だけ呼ばれます.
なので,出力は一回しかされないようにできます.
結構がっつり解説しましたがニュアンスが伝わればいいと思います.
平均を求める
❯❯❯ echo "1\n2\n3" | awk '{a += $1} END {print a/NR}'
2
❯❯❯ echo "1 2 3" | awk '{for (i = 1; i <= NF; i++) a += $i} END {print a/NF}'
2
NR
は行数と思ってもらうといいと思います.
頻度を求める
ここから少しトリッキーな感じになっていきます.
❯❯❯ echo "1\n2\n3\n1" | awk '{a[$1]+=1} END {for (i in a) print i "," a[i]}' | sort
1,2
2,1
3,1
まずa[$1]
でa
を連想配列のように扱えます.
そしてfor (i in a)
とすることで,key
を取り出せます.
後は出力しておしまいです.
連想配列の指定したkeyに値が存在しなければ,その中身が0なり空文字なりに色々なってくれてすごいけど,バグ起きたらやばそうという印象です.
❯❯❯ echo "1\n2\n3\n1" | awk '{a[$1]=a[$1] $1} END {for (i in a) print i "," a[i]}' | sort
1,11
2,2
3,3
❯❯❯ echo "hello\nworld\nsunday\nhello" | awk '{a[$1]=a[$1] $1} END {for (i in a) print i "," a[i]}' | sort
hello,hellohello
sunday,sunday
world,world
zip関数みたいなもの
pasteコマンドを利用します.
❯❯❯ ARR1=`seq 1 10`
❯❯❯ ARR2=`seq 21 30`
❯❯❯ paste <(echo $ARR1) <(echo $ARR2) | while read a b ; do echo $a $b ;done
1 21
2 22
3 23
4 24
5 25
6 26
7 27
8 28
9 29
10 30
❯❯❯ paste <(for i in `seq 1 10`;do echo $i;done) <(for i in `seq 21 30`;do echo $i;done) | while read a b ; do echo $a $b ;done
1 21
2 22
3 23
4 24
5 25
6 26
7 27
8 28
9 29
10 30
これによって,二つの異なるパラメータが入ったarrayを回してプログラムの引数にしたりなんかもできたりします.
そしてここでちゃっかりプロセス置換というものを利用しています.
このプロセス置換というものは,コマンドの書き込み先をそのままコマンドに渡せるという感じのものです.
これの何が嬉しいのかというと,ファイルを作成しなくてもファイルを参照するようなコマンド(diffなど)に値を渡せます.
diff <(hoge) <(hoge)
などはよく使うので,覚えておくと良さげだと思います.
❯❯❯ echo <(echo hello)
/dev/fd/12
指定ディレクトリ内のファイルを回す
❯❯❯ ls dir
a.csv b.csv c.csv
❯❯❯ for i in dir/*.csv ;do echo $i hello;done
dir/a.csv hello
dir/b.csv hello
dir/c.csv hello
❯❯❯ find dir -name "*.csv" | while read file ;do echo $file hello ;done
dir/a.csv hello
dir/c.csv hello
dir/b.csv hello
❯❯❯ find dir -name "*.csv" | xargs -I@ echo @ hello
dir/a.csv hello
dir/c.csv hello
dir/b.csv hello
好きなものを使えばいいと思っています.
個人的にはfind
書いて,while read
していることが多い.
置換
sed
コマンドをよく使います
❯❯❯ echo "hello\nworld\nsunday\nhello" | sed 's/he/hu/g' | sed 's/su/mo/g'
hullo
world
monday
hullo
❯❯❯ cat test.csv
a
b
c
d
a
❯❯❯ sed -i -e 's/a/g/g' test.csv
❯❯❯ cat test.csv
g
b
c
d
g
❯❯❯ cat test.csv-e
a
b
c
d
a
sed -i <extension>
と書くことで,書き換えを行う前のファイルのバックアップが取られます.
その時のバックアップファイル名は,fileName + <extension>
となります.
設定ファイルを少し書き換えたい時なんかは,結構便利です.
まとめ
とりあえず僕がよく使ってきたコマンドたちを紹介しました.
この機会にぜひShellと戯れてくださいね.
おまけ
僕はターミナルで長いコマンドを打ったりするのですが,その時にはzshを利用しています.
zshの良い点として,vim modeなるものがあります.(bashにもあるらしい)
これはvimのようにノーマルモード,インサートモード,ヴィジュアルモードと切り替えができるだけでなく,アンドゥなどもできます.
だからとりあえず少しミスっても安心感がでかく,ずっとShellで長いコマンドを書き続けられています.(それがいいのかは知らない)
皆さんも興味があればぜひ使ってみてください.