大量のExcelファイルを簡単に一括でCSVに変換する方法

## はじめに
この記事は大量のエクセルのデータをCSVに簡単、迅速、綺麗に一括変換する方法の紹介記事です。
手順等を詳しく書くように心がけましたので非エンジニアの人にも広く使ってもらえると幸いです。

## 動作確認環境
- Windows 10

※Macでは動作確認ができていませんが、シェルスクリプトを使った変換であるため動作すると思います

## 達成できる内容

- 指定フォルダ内にあるExcelブックを一括でCSVに変換することができます
- 変換後のCSVはExcelで文字化けなく開くことができます
- 変換途中の状況を画面上で確認することができます

※シェルスクリプトの改変によって上記を拡張、変更することが可能です

## 使用技術

- Git Bash（Windows環境でコマンドを実行するため）
- pip（Python用のパッケージ管理システム）
- xlsx2csv（Pythonのライブラリ）
- シェルスクリプト

## 下準備
### 1.Git Bashのダウンロード
Windows環境でシェルスクリプトを実行するためのツールとしてGit Bashを使います。
Git BashはGitをインストールすることで入手することができます。
下記の「step1.Git Bashのダウンロード」を参考にインストールします。

https://sukkiri.jp/technologies/devtools/git/git_win.html

### 2.pipのインストール

CSVの一括変換にはPythonのライブラリを使用します。
Pythonのライブラリをインストールするためには、pipが必要な為、先にpipをインストールします。
なお、pipはPythonをインストールすることで自動的に付属してきます。
下記の「1. Pythonのインストール」を参考にPythonをインストールします。

https://prog-8.com/docs/python-env-win

### 3.xlsx2csvのインストール
https://sukkiri.jp/technologies/devtools/git/git_win.html

上記の「step2.Git Bashの実行」を参考にGit Bashを起動します。

Git Bashの画面に下記のコマンドを打ち込み、xlsx2csvをインストールします。

```bash
pip install xlsx2csv
```

なお、正常にインストールできている（すでにインストール済みの）場合は再度上のコマンドを実行した際、

```bash
Requirement already satisfied
```

というメッセージが最初に表示されますので、インストール済みであることが確認できます。
以上で下準備は終了です。
※なお、pipのバージョンが古いとWARNINGが出る場合がありますが、今回のインストールには直接影響はありません

## Excelを一括でCSVに変換するためのシェルスクリプト
###フォルダ構成例
```
Sample（親フォルダ）
  ├── convert.sh（変換用のシェルスクリプトファイル）
  ├── edit（Excelファイルを保存しているフォルダ）
  │     ├── hogehoge1.xlsx
  │     ├── hogehoge2.xlsx
  │     └── hogehoge3.xlsx
  └── main（CSVファイルの出力先フォルダ）
```

###シェルスクリプト
メモ帳（テキストエディタ）を開き、下記シェルスクリプトをコピー＆貼り付けします。
ファイル名をconvert.shとして、上記の配置になるようにファイルを保存します。

```shell
#!/bin/bash

save_dir="./main/"
file="data_timestamps.csv"

if [ -f $file ] ; then
  rm data_timestamps.csv
fi

touch data_timestamps.csv
echo "table_name,last_updated_datetime" >> data_timestamps.csv

for filepath in `find ./edit/ -name '*.xlsx'`
do
  filename=`basename ${filepath} .xlsx`
  filename_offset=${filename:0:2}

  if [ ${filename_offset} = "~\$" ] ; then
    echo -e "\033[0;31mError:${filename}\033[0;39m"
    continue
  fi

  xlsx2csv -s 1 $filepath $save_dir$filename.csv
  sed -i '1s/^/\xef\xbb\xbf/' $save_dir$filename.csv
  touch -t `date "+%Y%m%d%H%M.%S" -r $filepath` $save_dir$filename.csv
  echo  "$filename,`date "+%Y-%m-%d %H:%M:%S" -r $filepath`" >> data_timestamps.csv
  echo -e "\033[0;32mSuccess:${filename}\033[0;39m"
done

echo ${SECONDS} seconds
read -p "Complete. Press any key: "
```

###使い方
該当のシェルスクリプトをダブルクリックすることでCSV変換処理を実行することができます。
なお、シェルスクリプトは実行する度にCSVファイルを上書きします。

## 詳細説明（※エンジニア向け）
```
save_dir="./main/"
file="data_timestamps.csv"
```
ファイルの出力先、出力詳細のファイル名を指定します。

```
if [ -f $file ] ; then
  rm data_timestamps.csv
fi
```
出力詳細のファイルは毎回生成し直したいため、存在していた場合あらかじめ削除します。

```
touch data_timestamps.csv
echo "table_name,last_updated_datetime" >> data_timestamps.csv
```
出力詳細のファイルを作成、ヘッダーとなる内容をあらかじめ作成しています。

```
for filepath in `find ./edit/ -name '*.xlsx'`
do
　繰り返したい処理
done
```
editフォルダ内にある.xlsxファイルを取得し、1ファイルずつループ処理しています。

```
filename=`basename ${filepath} .xlsx`
filename_offset=${filename:0:2}

if [ ${filename_offset} = "~\$" ] ; then
  echo -e "\033[0;31mError:${filename}\033[0;39m"
  continue
fi
```
ファイル名の先頭から2文字を変数に代入しています。
先頭からの二文字が
```~$```
であった場合はCSV変換の対象外としています。
Excelはファイル編集中の場合、~$hogehogeというファイルが別途作られるため除外しています。

```
xlsx2csv -s 1 $filepath $save_dir$filename.csv
sed -i '1s/^/\xef\xbb\xbf/' $save_dir$filename.csv
touch -t `date "+%Y%m%d%H%M.%S" -r $filepath` $save_dir$filename.csv
echo  "$filename,`date "+%Y-%m-%d %H:%M:%S" -r $filepath`" >> data_timestamps.csv
echo -e "\033[0;32mSuccess:${filename}\033[0;39m"
```

上記の1行目でExcelファイルをCSVに変換し出力しています。
2行目で出力したCSVが文字化けしないようにUTF-8 BOM付きにしています。
3行目で生成したCSVの更新日時をExcel側の更新日時と同期しています。
4行目で出力詳細のファイルへ出力ログとして内容を書き込みしています。
5行目でCSV変換が成功したことを色付きテキストで表示しています。

```
echo ${SECONDS} seconds
read -p "Complete. Press any key: "
```
実行にかかった時間を表示し、ユーザーのボタン入力があるまでは画面が勝手に閉じないようにしています。

## 補足資料及び調べた時に役に立ったページ
https://eng-entrance.com/linux-shellscript-do

https://shellscript.sunone.me/

https://qh73xebitbucketorg.readthedocs.io/ja/latest/1.Programmings/python/LIB/xlsx2csv/main/

https://r-h.hatenablog.com/entry/20110119/1295452747

https://qiita.com/koara-local/items/04d3efd1031ea62d8db5

https://qiita.com/kg1/items/cb390f90ae4758e4c5ca

https://qiita.com/huushihi/items/c7f578bf51c0017c9076

https://qiita.com/tamanugi/items/63fe5cf8e709565777a5

https://scrapbox.io/dai-yamamoto/sed%E3%81%A7BOM%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B

https://tech.pepabo.com/2021/03/19/remove-the-bom-when-importing-csv/