概要
特定の文字列を含むエクセルファイルがどこにあるのか、エクセルファイルを開かずに検索したい時もある。(※1)
方法は色々ある(※2)が、今回はシェルスクリプトでやってみる。(何でもシェルスクリプトでやりたくなってしまう悪い癖ですねほんと。。。)
基本的にはMacで動かしていますが、bashが動く環境ならWindowsでもLinuxでも動くはず。多分。(WindowsのGitBashでなら確認しました!)
※1:試してはないが、エクセルだけでなくOffice系ファイルは同じ方法でいけるはず。今回のシェルスクリプトを、エクセルファイルだけでなくOffice系ファイル全般に使えるスクリプトにアレンジすることもできるはず。
※2:Macならmdfindコマンドとか
カラクリ
どうやってExcelファイルを全文検索するのか。
知っている人も多いと思うが、実はエクセルファイルというのは、xmlファイル群をzipで固めたものだ。
だから、zipを解凍して全xmlファイルについてgrepをかけてやればエクセルファイルの全文検索が可能ということだ。
シェルスクリプトのコード
エクセルファイルを全文検索するシェルスクリプトのコードは以下の通り。
#!/bin/bash
main() {
# 引数からgrepの操作内容を取り出す
operation=""
for arg in "${@}"; do
if [ $(echo ${arg} | grep -vE '\.xlsx$|\.xls$') ]; then
# FIXME シングルクォーテーションが消えてしまう
operation=${operation}" "${arg}
fi
done
# 一つ一つのxlsxファイルに対してgrepする
for arg in "${@}"; do
# *.xlsx以外の引数の場合何もしない
if [ $(echo "${arg}" | grep -vE '\.xlsx$|\.xls$') ]; then
continue
fi
# 一時ファイルなら何もしない
if echo "${arg}" | grep -qE '^~\$'; then
continue
fi
target_file="${arg}"
# zip展開用一時ディレクトリ作成
tmpdir=$(mktemp -d)
# grepの標準出力用一時ファイル作成
tmpgrep=$(mktemp)
# エクセルファイルを一時ディレクトリに解凍する
# 標準出力とエラー出力は鬱陶しいので捨てる
unzip "${target_file}" -d "${tmpdir}" 1>/dev/null 2>&1
# 全xmlファイルにgrepする
find ${tmpdir} -type f \
| grep -E 'xml$' \
| xargs -I{} grep ${operation} {} \
| tr '\"' '\n' \
| tr '>' '\n' \
| sed -e 's/<\/.*//' \
| grep ${operation} >${tmpgrep}
# 検索文字列があればファイル名とその内容を出力する
if [ $? = 0 ]; then
# FIXME
# awkを使って出力しているので、
# grepの--color=autoが効かない
cat ${tmpgrep} | awk '{print filename": "$0}' filename="${target_file}"
fi
# 一時ディレクトリとファイルを削除
rm -r ${tmpdir}
rm ${tmpgrep}
done
}
main "${@}"
インストール方法
(1)PATHが通っているディレクトリに配置するか、配置したディレクトリのPATHを通す
例)
・~/binというディレクトリを作成し、本スクリプトを配置
・~/binのPATHを通す
(2)実行権限を与える
chmod +x excelgrep
使用方法
基本的にgrepコマンドと同じような使い方ができる。
# カレントディレクトリ内のエクセルファイルに対して全文検索を行う
excelgrep '検索文字列' *.xlsx
# カレントディレクトリ以下の全てのディレクトリ内のエクセルファイルに対して全文検索を行う
find . -type f | grep -E 'xlsx$' | xargs -I{} excelgrep '検索文字列' {}
使用例
普通にgrepコマンドのように使用し、同じように出力を得ることができる。
$ excelgrep 'test' *.xlsx
test1.xlsx: test1
test2.xlsx: test2
test3.xlsx: test3
オプション
基本的にgrepコマンドと同じオプションが使える。
-
大文字小文字を区別しない
→-i
-
正規表現
→-E
例)大文字小文字を区別しないor検索
excelgrep -iE '検索文字列1|検索文字列2' *.xlsx