コマンドライン 初級〜中級者に役立つコマンド７選（逆引き）

# 導入

コマンドラインの基本操作程度は分かるけど、shellスクリプトを書いたりするにはどうも使いこなせるコマンドの手駒が少ない……という方もいると思います。そうした方向けに、文字列操作・ファイル操作に役立つコマンド７つをまとめました。　　
 
# 前提

コマンドラインの基本操作もままならない……という方は、以下の基本操作程度を身につけていただければと思います。

[基本コマンドプロンプト25選！逆引きコマンド一覧](https://proengineer.internous.co.jp/content/columnfeature/5007#section112)
[Introduction to Bash](https://astrobiomike.github.io/bash/bash_intro_binder#all-commands-presented-here)

# 本記事で紹介するコマンド一覧（逆引き）


| したい事       | コマンド名 | 
|:-----------------|:-----------------|
|ファイル名を検索したい|[find](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#findコマンド), [grep -l](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#grep--l-コマンド) |
| 文字列を検索したい(= ファイル内で、ある文字列を含む**行**だけ取り出したい)      | [grep](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#grepコマンド) |
|ある**列**だけ取り出したい|[cut](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#cutコマンド)|
|文字を縦方向にくっつけたい（＝行をくっつけたい）| [cat](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#catコマンド) |
|文字を横方向にくっつけたい（＝列をくっつけたい）| [paste](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#pasteコマンド) |
|ある行を削除したい|[sed](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#sedコマンド) |
|ある文字を別の文字で置き換えたい| [sed](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#sedコマンド) |
|ある文字を別の文字で置き換えたい(\nなど特殊文字を含む場合)| [tr](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#trコマンド) |
|フィルタリングしたい(= ある数値的な条件を満たす行のみ取り出したい)| [awk](https://qiita.com/satoru_pripara/items/60cbd0f10ae39e3f7a9f#awkコマンド) |
|集計したい|[awk](https://qiita.com/drafts/60cbd0f10ae39e3f7a9f/edit#awkコマンド)|

※ 「列」とは文字の縦の並びのことを言います。英語では"Column", "Field"です。
※ 「行」とは文字の横の並びのことを言います。英語では"Row"です。

# 各コマンド詳細

### findコマンド
- ファイル名を検索したい（現在のワーキングディレクトリ内部）
   - `find ファイル名`

- "abc"という文字から始まるファイル名を検索したい（現在のワーキングディレクトリ内部）
   - `find abc*`

- あるフォルダの中でファイル名を検索したい
   - `find フォルダ名 -name ファイル名`     

### grepコマンド


- 文字列を検索したい(= ファイル内で、ある文字列を含む**行**だけ取り出したい)
   - `grep "検索文字列" ファイル名` 
   - 例
      - `grep "Final" example.txt`
         - example.txtの中から、Finalという文字列を含む行を抜き出す。
      - `grep "Start\|Final" example.txt`
         - example.txtの中から、StartまたはFinalという文字列を含む行を抜き出す。`\`はエスケープ文字で、`|`は論理和演算子。
      - `grep "Start|Final" example.txt`
         - example.txtの中から、Start|Finalという文字列を含む行を抜き出す。`\`がないと`|`は論理和演算子として認識されない。 
      - `grep "Start" example.txt | cut -f3` 
         - example.txtの中からFinalという文字列を含む行を抜き出す。その結果から、さらに３列目のみを抜き出す。
      - `grep "Start" example.txt | cut -f1,3,4,6 > new_example.txt` 
         -  example.txtの中からFinalという文字列を含む行を抜き出す。その結果から、さらに１、３、４、６列目のみを抜き出し、new_example.txtに出力する。
      - `grep -c "Critical" example.txt`
         -  example.txtの中で、Criticalという文字列が含まれている行の数を返す。１行に２つ以上含んでいても、１行とカウントされる。オプションの`c`はcountの意。
      - `grep -w "behave" *` 
         - 現在のディレクトリ直下の全ファイルを検索し、behaveが完全一致でヒットする行を返す。 -wオプションは、wordを表す。
      - `grep -r "abc" Temporal`
         - 現在のディレクトリにあるTemporalの中から"abc"という文字列のある行を再帰的に返す。再帰的とは、サブディレクトリがある場合その中身も検索するという意味(`r`は recursive 再帰的の略)。
      - `grep -i "abc" *`
         - 現在のディレクトリ直下の全ファイルを検索し、 大文字・小文字の区別はしないで"abc"という文字を含む行を返す。iは、ignoring caseの略。

### grep -l コマンド

- `grep -l "abc" *`
   - 現在のディレクトリにあるTemporalの中から"abc"という文字列を含む行を持つファイルの**ファイル名**を返す。lは、listの略。
         
### cutコマンド

- ある**列**だけ取り出したい
   - `cut -f1 ファイル名` ※数字は、左から何列目かを指す。
   - 例
      - `cut -f2 example.txt` 
         - example.txtの２列目のみ抜き出す
      - `cut -f2,4,6 example.txt` 
         - example.txtの２、４、６列目を抜き出す
      - `cut -f1-4,6 example.txt` 
         - example.txtの１、２、３、４、６列目を抜き出す。
      - `cut -f1-4,6 example.txt > new_example.txt`
         - example.txtの１、２、３、４、６列目を抜き出し、new_example.txtに出力する。
      - `cut -d "," -f1-4,6 example.csv` 
         - 列を区切る基準を","として、example.csvの１列目から４列目、および６列目を抜き出す（オプションの`-d`はdelimiter 区切り文字の意）。csvファイルはカンマ区切りであるため、`-d`オプションでカンマを指定することも多いと思われる。

### catコマンド

※catとはconcatenate（文字列の結合）を意味します。

- 文字を縦方向にくっつけたい（＝行をくっつけたい）
   -  `cat ファイル名　別のファイル名`
   -  例
      - `cat upper.txt lower.txt > result.txt`
         - upper.txtの内容の下にlower.txtの内容をくっつけ、result.txtに出力する。    

### pasteコマンド

- 文字を横方向にくっつけたい（＝列をくっつけたい）
   - `paste ファイル名 別のファイル名` 
   - 例
      - `paste left.txt right.txt` 
         -  left.txtの右に、right.txtの内容を貼り付けた結果を表示する。両ファイルの中身はtabで区切られる。
      - `paste -d ' ' left.txt right.txt`
         -  left.txtの右に、right.txtの内容を貼り付けた結果を表示する。両ファイルの中身は半角スペースで区切られる。-dはdelimiter　区切り文字を表し、任意の区切り文字を指定できる。
      -  `paste left.txt right.txt > result.txt`
         -  left.txtの右に、right.txtの内容を貼り付け、result.txtに出力する。
      - `paste left.txt right.txt | cut -f1,3,4,6,10 | grep "Karate\|Judo" > result.txt`
         -   left.txtの右にright.txtの内容を貼り付け、その結果のうち左から１、３、４、６、１０列目を抜き出し、その結果のうちKarateまたはJudoという文字列を含む行のみ抜き出し、その結果をresult.txtに出力する。

### sedコマンド

sedとはStream Editorの略で、非常に幅広い機能があります。よく使いそうな機能のみ示します。

- ある行を削除したい
   - `sed '1d' ファイル名`　※1行目を削除したい場合
   - 例
      - `sed '1d' example.txt`
         - example.txtの中身の1行目を削除したものを表示する。   
      - `cut -f3 -d ',' example.csv | sed '1d' > result.txt` 
         - example.csvファイルについて、カンマ区切りで数えて左から3列目を取り出す。その結果について、1行目を削除する。その結果を、result.txtに書き込む。

- ある文字を別の文字で置き換えたい 
   -  `sed 's/置き換え元の文字列/置き換え先の文字列/' ファイル名`
   - 例
      - `sed 's/Nobunaga/Hideyoshi/' Leader.txt`  
         -  Leader.txtのうちNobunagaという文字列をHideyoshiに書き換える。ただし一行のなかでNobunagaという言葉が複数あった場合は、一番左の物のみ置き換えることに注意。sという文字はsubstitute 置き換えを表している。
      - `sed 's/Nobunaga/Hideyoshi/g' Leader.txt` 
         -  Leader.txtのうちNobunagaという文字列をHideyoshiに書き換える。gという文字はglobalを表し、一行のなかに置き換えたい単語が複数あった場合でも、全て置き換える。

### trコマンド

※trとはtranslationを意味します。

 - ある文字を別の文字で置き換えたい(\nなど特殊文字を含む場合)
    - `tr "置き換え元の文字列" "置き換え先の文字列" < ファイル名` 
    - 例
       - `tr "\r" "\n" < excel_exported_file.txt > result.txt` 
          - excel_exported_file.txt内の\rを全て\nに置き換え、その結果をresult.txtに出力する。Excelからエクスポートされたファイルは、改行に一般的な改行文字\nでなく\rを使っているため使い所があると思われる。対象となるファイルを`<`で示していることに注意。
       - `cut -f1,2 example.txt | tr "\t" "\n" > result.txt`
          -  example.txtの左から１、２列目のみを取り出す。その結果について、tab区切りの部分を全て改行に変え、result.txtに出力する。

### awkコマンド

※awkとは開発者のAlfred Aho, Peter Weinberger, Brian Kernighanの姓の頭文字をとったものだそうです。非常に幅広い使い方がありますが、単純なもののみ示します。

- フィルタリングしたい(= ある数値的な条件を満たす行のみ取り出したい)
   - `awk '条件文' ファイル名`
   - 例
      - `awk '$1 > 180' example.txt`
         - example.txtの中で、1列目の数値が180より高い行のみ選び出し表示する。
      - `awk '$1 > 180 && $2 < 70' example.txt`  
         -   example.txtの中で、1列目の数値が180より高く、かつ２列目の数値が70より低い行のみ選び出し表示する。`&&`は論理積演算子を表す。
      - `awk '$1 > 180 && $2 < $1^2*19' example.txt`  
         -  example.txtの中で、1列目の数値が180より高く、かつ２列目の数値が１列目の数値の２乗の１９倍より低い行のみ選び出し表示する。
      -  `awk '$3 <= 195 || $3 > 900' example.txt`  
         -  example.txtの中で、3列目の数値が195以下か、または900より大きい行のみ選び出し表示する。`||`は論理和演算子を表す。

- 集計したい
   - `awk '{sum += $1} END {print sum}' ファイル名` ※$1とは、ファイル内の左から一列目を集計することを表す。
   - 例
      - `awk '{sum += $6} END {print sum}' example.txt` 
         - example.txtの6列目の数値の合計値を表示する。`sum`は変数名のため、違う文字列でも良い。
      - `grep -w "^42" * | cut -f7 | awk '{sum += $1} END {print sum}'`
         - 現在のディレクトリ直下の全ファイルを検索し、先頭が42である行を選び出す。その結果のうち、左から７列目のみを選び出す。その結果について、全列の数値の合計を出力する。 
      - `awk '{sum += $2} {print sum}' example.txt`
         - example.txtの2列目の数値の合計値を表示する。ENDがないため、集計中の各行ごとの途中経過も表示される。例えば、以下のようになる。最も下の値が最終的な合計値となる。


```
MyPC:MyFolder user$ awk '{sum += $2} {print sum}' example.txt
0
13
65
134
747
1003
```

# 合わせ技

各コマンドを合わせるとさらに複雑なタスクができるようになります。シェルスクリプトを書く時などにも役立ち、日々の業務効率改善につながるでしょう。

##### テキストファイルにヘッダーをつける
```
head -n1 example.txt | cut -f1,3,4,6 > temp_header
cat temp_header product.txt > temp_new_product
rm temp_header
mv temp_new_product product.txt
```

example.txtの上から一行目を取り出す。その内の左から１、３、４、６列目を取り出し、temp_headerファイルに保存する。
temp_headerの下にproduct.txtの内容をくっつけて、temp_new_productファイルに書き込む。
temp_headerファイルを消す。
temp_new_productをproduct.txtにリネームする。


##### 多数のファイルを一気にリネームする。

ディレクトリ内にbefore_replace1.txt, before_replace2.txt〜before_replace1000.txtというファイルが１０００個あると仮定してこれらをリネームするスクリプト。

```
ls *.txt > original_filenames
tr "before_replace" "after_replace" < original_filenames > new_filenames
paste -d ' ' original_filenames new_filenames > both_filenames
sed 's/^/mv /' both_filenames > rename_all.sh
rm *filenames
bash rename_all.sh
```
末尾が.txtで終わるファイルのファイル名一覧を取得し、その結果をoriginal_filenamesファイル書き込む。
そのファイル名一覧について、before_replaceの文字を全てafter_replaceに置き換え、new_filenamesファイルに書き込む。
区切り文字を半角スペースとして、original_filenamesの中身の右側にnew_filenamesの中身をくっつけ、both_filenamesに出力する。
both_filenamesの各行の行頭に"mv "を追加し、rename_all.shを追加する。rename_all.sh内には、ファイル名を書き換えるmvコマンドが１０００個書かれているということになる。
original_filenamesファイル、new_filenamesファイルは不要なので削除する。
rename_all.shを実行する。  

# 終わりに

紹介したコマンドは、全て自分でも実行していますが、間違いなどあれば教えてください。

# 参考

[Happy Belly Bioinformatics - Six glorious commands worth getting to know](https://astrobiomike.github.io/bash/six_commands#getting-started)
[Happy Belly Bioinformatics - Why is this all worth it?](https://astrobiomike.github.io/bash/why)
[Regular expressions quick reference](https://www.computerhope.com/unix/regex-quickref.htm)
[Learning Linux Commands:Sed](https://linuxconfig.org/learning-linux-commands-sed)
[sed, a stream editor](https://www.gnu.org/software/sed/manual/sed.html#sed-script-overview)
[How to use the grep command in Linux](https://www.web24.com.au/tutorials/use-grep-command-linux)
[GeeksforGeeks - Paste command in Linux with examples](https://www.geeksforgeeks.org/paste-command-in-linux-with-examples/)
[【Linux】特定の文字列を含むファイル名を表示する](https://qiita.com/yukibe/items/d250c18b177357340042)
[エンジニアの入口 - ファイルなどを検索する！findコマンドの詳細まとめ【Linuxコマンド集】](https://eng-entrance.com/linux-command-find)