Shift_JIS,CRLFに一括変換・確認するシェル

## はじめに

Shift_JIS,CRLFへの文字コード・改行コード変換(ついでに確認も)するために作ったシェルをまとめておきます。
ピンポイントで求めてる方がいれば、かなり時間短縮できるかと・・・！
(逆にUTF-8へ変換したい場合やLFに変換したい場合もちょこっと弄ればできるはずです。)

※前提としてnkfコマンドを活用しているので、事前にインストールしておいてください。

## ①ディレクトリ以下のファイルをすべてShift_JIS,CRLFに変換する

```shell:conversion.sh
# ディレクトリ以下全て変換
echo 開始！

# 対象のディレクトリ
path="/c/development"

# 出力された全ファイルをfile_pathsに代入
file_paths=`find $path* -type f | sed 's/^'$path'//' `

for file_path in $file_paths;
do
  # ここで絶対パスにしてる。
  file=$path$file_path

  # ファイルの存在チェック(パス)
  if [ -e $file ]; then

    # 文字コードのチェック
    character_code=`nkf -g $file`

    # BINARYファイルはスキップ
    if [ ${character_code} = "BINARY" ] ; then
      continue
    fi

    # Shift_JIS以外のファイルをShift_JIS,CRLFに変換(後続の処理はスキップ)
    if [ ! ${character_code} = "Shift_JIS" ] ; then
      echo $file
      echo 変換前`nkf --guess $file`
      nkf -sc --overwrite $file
      echo 変換後`nkf --guess $file`
      echo --
      continue
    fi

    ## ここからShift_JISファイルの改行コード変換処理

    # 改行コードのチェック(sedコマンドで文字コード部分だけ取り出し)
    lf_code=`nkf --guess $file | sed -e "s/^.*(\(.*\)).*$/\1/" `

    # CRLF以外(LFもしくはMIXED NL)ならShift_JIS,CRLFに変更
    if [ ! "${lf_code}" = "CRLF" ] ; then
    # if [ "${lf_code}" = "LF" ] || [ "${lf_code}" = "MIXED NL" ] ; then # こっちでもOK
      echo $file
      echo 変換前`nkf --guess $file`
      nkf -sc --overwrite $file
      echo 変換後`nkf --guess $file`
      echo --
    fi

  fi
done

echo 終わり！
```

出力結果

```terminal:gitbash
$ sh conversion.sh
/c/development/hoge.java
変換前UTF-8 (LF)
変換後Shift_JIS (CRLF)
--
/c/development/hoge3.java
変換前Shift_JIS (LF)
変換後Shift_JIS (CRLF)
--
```

注意点
・CP932はShift_JISにならずCP932のままになるみたいです。ASCIIについても同じまま(BINARYと同じくスキップしてもいいかも)。
・`MIXED NL`で半角スペースが含まれる可能性があるので条件文の中の`lf_code`はダブルクォーテーションで囲んでる。
・Shift_JISファイルの改行コード変換でsオプションでShift_JISと明示せずに変換すると`ISO-2022-JP`になる。

`nkf -sc --overwrite $file`を全ファイルに実行するのもありっちゃありなんですが、
そうすると既存のShift_JIS,CRLFファイルなどターミナルに出力されて見にくいので条件分岐で絞り込みました。

## ②対象のファイルのみShift_JIS,CRLF変換する

ディレクトリ以下でじぶんの編集したソースだけ変換したい！みたいな場合は以下を実行！

```sh:conversion_narrow.sh
# 対象のファイルのみ変換する
echo 開始！

# 対象のディレクトリ
path="/c/development/"

# 対象のファイル(git statusとかで出した対象のファイルをここに書く。)
file_paths=(
  "product1/aaa.java"
  "product1/bbb.java"
  "product2/ccc.java"
)

for file_path in ${file_paths[@]};
do
  file=$path$file_path

  # ファイルの存在チェック(パス)
  if [ -e $file ]; then

    # 文字コードのチェック
    character_code=`nkf -g $file`

    # BINARYファイルはスキップ
    if [ ${character_code} = "BINARY" ] ; then
      continue
    fi

    #Shift_JIS以外ならShift_JIS,CRLFに変換(後続の処理はスキップ)
    if [ ! ${character_code} = "Shift_JIS" ] ; then
      echo $file
      echo 変換前`nkf --guess $file`
      nkf -sc --overwrite $file
      echo 変換後`nkf --guess $file`
      echo --
      continue
    fi

    #改行コードのチェック(sedコマンドで文字コード部分だけ取り出し)
    lf_code=`nkf --guess $file | sed -e "s/^.*(\(.*\)).*$/\1/" `

    # CRLF以外(LFもしくはMIXED NL)ならShift_JIS,CRLFに変更
    if [ ! "${lf_code}" = "CRLF" ] ; then
      echo $file
      echo 変換前`nkf --guess $file`
      nkf -sc --overwrite $file
      echo 変換後`nkf --guess $file`
      echo --
    fi

  fi
done

echo 終わり！
```

出力結果

```terminal:gitbash
$ sh conversion.sh
/c/development/product1/aaa.java
変換前UTF-8 (LF)
変換後Shift_JIS (CRLF)
--
/c/development/product2/ccc.java
変換前Shift_JIS (LF)
変換後Shift_JIS (CRLF)
--
```

ソース的には①をちょこっと弄っただけ。

## ③ディレクトリ以下のファイルすべての文字コード、改行コードを確認する※シェル不要

`$ find . -type f | xargs nkf --guess | column -s: -t`

あとは変換漏れを確認するためにShift_JISを除いて出力させるのもありですね◎

`$ find . -type f | xargs nkf --guess | column -s: -t | grep -v "Shift_JIS"`

## ④対象のファイルのみ文字コード、改行コードを確認する

```sh:check.sh
# 対象のファイルのみ確認する
echo 開始！

# 対象のディレクトリ
path="/c/development/"

# 対象のファイル
file_paths=(
  "product1/aaa.java"
  "product1/bbb.java"
  "product2/ccc.java"
)

for file_path in ${file_paths[@]}; do
  file=$path$file_path 
  echo $file
  nkf --guess $file | column -s: -t
  echo --
done

echo 終わり！
```
出力結果

```terminal:gitbash
$ sh check.sh
/c/development/product1/aaa.java
Shift_JIS (CRLF)
--
/c/development/product1/bbb.java
Shift_JIS (CRLF)
--
/c/development/product2/ccc.java
Shift_JIS (CRLF)
--
```

## おまけ　④からShift_JIS,CRLFを除いた対象ファイルを出力

Shift_JIS,CRLF除いた漏れ分のみ出力させるなんかもありかも。ってことで追記。

```sh:check.sh
# 対象のファイルのみ確認する
echo 開始！

# 対象のディレクトリ
path="/c/development/"

# 対象のファイル
file_paths=(
  "product1/aaa.java"
  "product1/bbb.java"
  "product2/ccc.java"
)

# 確認対象のファイル数をカウント
total="${#file_paths[@]}"

# Shift_JIS,CRLFになっていないファイルをカウントするための変数
count=0

for file_path in ${file_paths[@]}; do
  file=$path$file_path
  check=`nkf --guess $file`
  if [ ! "${check}" = "Shift_JIS (CRLF)" ] ; then
    echo $file
    nkf --guess $file | column -s: -t
    let count++
    echo --
  fi
done

echo "Shift_JIS,CRLFになっていないファイルは$count/$totalです"

echo 終わり！
```
出力結果

```terminal:gitbash
$ sh check.sh
/c/development/product1/aaa.java
Shift_JIS (LF)
--
Shift_JIS,CRLFになっていないファイルは1/3です
終わり！
```

## 追記　CRLFからLFに一括変換

最近はLFにするケースの方が多いと思うので追記します。
※変換する前に一度echoで対象ファイルがあっているか確認することをお奨めします。

```sh:check.sh
# ディレクトリ以下全て変換
echo 開始！

# 対象のディレクトリ(/は不要)
path="."

# 出力された全ファイルをfile_pathsに代入
# （補足）findで指定したフォルダ以下のファイルを出力。sedで重複するパスの部分を除去。
file_paths=`find $path* -type f | sed 's/^'$path'//' `

for file_path in $file_paths;
do
  # ここで絶対パスにしてる。
  file=$path$file_path

  # ファイルの存在チェック(パス)
  if [ -e $file ]; then

    # 文字コードのチェック ※ UTF-8の場合はUTF-8と代入される。
    character_code=`nkf -g $file`

    echo $file
    echo 変換前`nkf --guess $file`
    # LF変換
    nkf -Lu --overwrite $file
    # CRLF変換
    # nkf -Lw --overwrite $file
    echo 変換後`nkf --guess $file`
    echo --
    continue

  fi
done

echo 終わり！
```


## 最後に

書いてるうちに、条件分岐こっちの方がシンプルじゃん！とか、
変数内に半角スペースあるとエラるじゃん！みたいな気づきもあって、
定期的にアウトプットする重要性を再認識しました。

## 参考になる記事

[新人さんに知ってほしい「文字コードのお話」](https://qiita.com/yuji38kwmt/items/b3a7820b4d3b544da4ff)
[【 nkf 】コマンド――文字コードと改行コードを変換する](https://www.atmarkit.co.jp/ait/articles/1609/29/news016.html)
[シェルスクリプトの条件評価ではまりやすいところ](http://ritchiekotzen.hatenablog.com/entry/20090430)
[シェルスクリプトに挑戦しよう（15）繰り返し処理の中断](https://www.atmarkit.co.jp/ait/articles/1901/30/news005.html)
[シェルスクリプト(bash)のif文とtestコマンド([])自分メモ](https://qiita.com/toshihirock/items/461da0f60f975f6acb10)
[bashでファイルやディレクトリの存在確認方法まとめ](https://qiita.com/nii_yan/items/73f4caacdc2ca6f45135)
[bash 配列まとめ](https://qiita.com/b4b4r07/items/e56a8e3471fb45df2f59)
[findコマンドの使い方](https://qiita.com/hana_shin/items/d1b420568d3c2223bd07)