ターミナル操作を快適にするTips集

ITエンジニア。
それは人生の半分をターミナル操作して過ごす生き物。

そんなITエンジニア諸氏に捧げるTips集です。

（訳：個人的に役に立ったTips集まとめてみた）

## 登場回数でソート
`<some_command> | sort | uniq -c | sort -nr`

使用回数が多くて自然と覚えてしまったヤツ。
何かと集計する時に便利。

```console
$ cat example.txt
aaa
bbb
aaa
ccc
bbb
aaa

# 集計
$ cat example.txt | sort | uniq -c | sort -nr
      3 aaa
      2 bbb
      1 ccc
```

## クオートを考慮してcut
`<some_command> | awk -v FPAT='([^,]+)|(\"[^\"]+\")' '{print $1}'`

CSVなんかは `cut` コマンドで特定の列取り出したりしますが、クオーテーションされてるとズレます。
UserAgent入りのログファイルなんかではあるあるですね。
なので、 `awk` コマンドの `FPAT` を指定してクオーテーションを考慮します。

```console
$ cat example.log
2021/01/01 00:00,"foo,bar",200
2021/01/01 01:00,foo,200
2021/01/01 01:00,bar,200

# cutコマンドだと崩れる
$ cat example.log | cut -d, -f2
"foo
foo
bar

# awkだクオーテーションも考慮できる
$ cat example.log | awk -v FPAT='([^,]+)|(\"[^\"]+\")' '{print $2}'
"foo,bar"
foo
bar
```

## クリップボードにコピー
Linux: `<some_command> | xsel -b` 
Mac: `<some_command> | pbcopy`

コマンド結果をコピペしてPRやSlackに貼ったりすることがよくありますよね？
いちいちマウスでターミナルから選択するのは面倒なので、 `xsel` や `pbcopy` コマンドを使えるようにしておくと便利でしょう。
これらのコマンドは標準入力をクリップボードに保存することができます。

余談：コマンドごとターミナルの一部をコピーしたいときは `tmux` のコピーモードを使っています。

## 繰り返し その1
`<some_command> | xargs <some_command>`

引数で複数ファイルを受け付けるコマンドの場合は問題ありませんが、1コマンド1ファイルしか対象とできないようなコマンドもあったりします。
そんなときは `xargs` で標準入力に対し繰り返しコマンド実行するテクニックが役立ちます。

`xargs -I{}` で `{}` を入力の変数として扱えることさえ覚えておけば様々な場面で役に立ちます。

```console
# .bak を末尾につけてmvする例
$ ls
a.log b.log

$ find ./ -type f | xargs -I{} mv {} {}.bak

$ ls
a.log.bak b.log.bak
```

実は `xargs` 使わずに実現できる例が多いですが、shell scriptに書く場合でなければ私は一番馴染みのある `xargs` 使いがちです。

## 繰り返し その2
`for f in $(<some_command>); do <some_command>; done`

`xargs` がうまく行かない場合などは諦めて気合で `for` ループをワンライナーで書きます。
ワンライナーなのは後述のヒストリーから呼び出す際に便利だからです。

```console
# .bak を末尾につけてmvする例
$ for f in $(ls -1); do mv $f $f.bak; done
```

ループ中にパイプで複数コマンドをつなげたり、変数を定義したりする際は `xargs` よりこっちを使っています。

## ヒストリーを使いこなす その1
zshユーザー向け。（fishには内蔵されている）

[zsh-users/zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) というzshのプラグインで導入します。
過去に利用したコマンドを前方一致で検索しサジェストしてくれます。


![スクリーンショット 2021-06-17 00-52-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/4dc82b26-b387-2cb2-ee7e-a0d3295014e0.png)

このように半透明で候補が表示され、候補を利用する場合はデフォルトでは `→` キーか `End` キーで確定できます。

bashとzshのデフォルトのヒストリサーチがこの挙動と似ていますが、後述するインクリメンタルサーチでキーマップを潰しているので、このサジェストはとても重宝してます。


## ヒストリーを使いこなす その2
`Ctrl + R` で呼び出すことのできるヒストリサーチをインクリメンタルサーチで置き換えます。

過去に以下の記事で `peco` を使った例を紹介しましたが、現在は `fzf` に落ち着きました。

https://qiita.com/reireias/items/fd96d67ccf1fdffb24ed

以下のような感じでコマンド履歴をインクリメンタルサーチできます。
![Peek 2021-06-17 01-10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/e99c6062-04c2-5093-9b43-5a61457db478.gif)

以下のような自作関数を `.zshrc` 中に定義して実現しています。

```zsh
# Ctrl + R = history search
function fzf-history-selection() {
    BUFFER=$(history -n 1 | tac  | awk '!a[$0]++' | fzf --no-sort --preview=)
    CURSOR=$#BUFFER
    zle reset-prompt
}
zle -N fzf-history-selection
bindkey '^R' fzf-history-selection
```

**これが無いと多分私はもう生きていけません**ってくらいには利用してます。

## リポジトリ管理
似た感じの `fzf` の使用例で、 `ghq` コマンドと組み合わせて高速にローカルのGitのディレクトリを移動するテクニックも便利です。
これもpecoの記事内に書いてあるのでそちらを参照してください。

gifだけ貼っておきます。（これは `fzf` の代わりに `peco` だけど）
![ghq](https://camo.qiitausercontent.com/31b24a17b884566b0b2a5d33433b836198b4d1b1/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3231343532362f31346531343665332d343236312d626464632d623463362d6162323337616433666331372e676966)

## Gitの状態とかいろいろ表示（プロンプトのカスタマイズ）
zshユーザー向け。

[romkatv/powerlevel10k](https://github.com/romkatv/powerlevel10k) というプラグインを利用すると、プロンプトのカスタマイズを簡単に行うことができます。

Gitのブランチやファイルの差分の有無等の各種ステータス、 `.xxx-versions` ファイルにより指定しているランタイムのバージョン情報を表示したり、かなりの自由度で設定可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/c9af80fc-24a3-b355-ab55-e55bddb8ea3e.png)

私の場合はこんな感じで設定しており、AWSのプロファイル名やランタイムのバージョン表示できることがありがたいです。

設定に関しては [こんな感じ](https://github.com/reireias/dotfiles/blob/c991f87fd537b29e3a4ce796bab700b4631c05af/.zsh/config/plugin.zsh#L20-L70) になっております。

## 画面分割
vimでもtmuxでもiTermの機能でもなんでもよいですが、ターミナル画面を分割し、自由に移動できるようにしておくと作業効率が上がるでしょう。
（ターミナルのウィンドウをたくさん並べて、この作業はどのターミナルでやってたっけ...？とターミナルをいくつも確認するエンジニアの多いことよ...）

私の場合はtmuxのwindowとpaneに加え、さらにvimの画面分割も使ったりします。

イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/a30ae865-d3be-e391-1a39-8ba2ef097bd8.png)


## 最後に
この辺のテクニックはだいたいは先輩方の画面を見て盗んで培ってきたものです。
リモートワーク中心だとこういったスキルを盗んで覚える機会が減ってしまう気がするけど、どうすればよいのでしょうか？

あと、「オレはこんなTips知ってるぜ」的なツイートが見てみたいので、是非。
（この記事の目的はコレ）