CSVファイル中のカラム数が異なるレコードをLinux上で手軽に検出する

目的

CSVファイルの中にある、不正なレコード(カラム数違い)を、できるだけ手軽に検出、修正する

動機

データの初期投入とかで、CSVからデータをインポートしたいが、ファイルの編集ミスやら、
エスケープ漏れなどで、うまくインポートができなくなってしまうことがある。
こういうとき、プログラムの改修やらログレベルの変更やらに頼らずに、簡単なコマンドだけで
不正なレコードを検出して、vimとかでちゃちゃっと直してしまいたい。

アプローチ

行ごとのカラム数を数えて、カラム数が異なる行を探す

結論

CSVのレコードがすべて正しい(カラム数が同一)ときは、下記のコマンドで「正しいこと」は確認できる

$ awk -F, '{print NF}' < sample.csv | uniq | wc -l
-> 1

このコマンドの実行結果が1であればすべてのカラム数が同じ。2以上なら、何かしら不正なレコードがある ことがわかる。

例えば、下記のように、3行目に不正なレコード(カラム数が5)を含んでいるCSVファイルだと、 結果は1にならない。

1,aaa,bbb,ccc
2,ddd,eee,fff
3,ggg,hhh,iii,jjj
4,kkk,lll,mmm
$ awk -F, '{print NF}' < sample.csv | uniq | wc -l
-> 3

この時、何行目が不正なレコード、つまり、カラム数が4でないレコードであるかを知るには、
下記のコマンドを実行すればいい。

$ awk -F, '{print NF"::"NR}' < sample.csv | grep -v '^4::'
-> 5::3

⇒ 出力が、 '5::3' と出たので、3行目に、カラム数5のレコードが存在していることがわかる。

レコードも一緒に見たい場合は、$0 も出力してやる

$ awk -F, '{print NF"::"NR, $0}' < sample.csv | grep -v '^4::'
-> 5::3 3,ggg,hhh,iii,jjj

解説(やってること)

awk の F オプションにカンマを指定することで、awk に渡す文字列のデリミタをカンマに変えることができる。
そのため、awk -F, '{print NF}'としてあげると、 「カンマ区切りで行を分割し、1行に含まれるフィールドの数を表示する」という動きになるので、
1行毎のカラム数を標準出力に出力してくれる。( NF は、フィールド数)

カラム数が正しいレコード(カラム数4)であれば、 "4:: " から始まるはずなので、これをgrep -v で
除外してあげれば、不正なレコードの行数だけを取得することができる。

応用編

ダブルクォートでカンマをエスケープしているCSVの場合

こんなCSVの場合

"aaa","bbb","ccc"
"ddd","eee","fff"
"ggg","hhh","iii"
"jjj","kkk","lll,mmm"

デリミタを , ではなく、"," にしてやる。(空レコードもダブルクォートでくくらていることを想定)

$ awk -F'","' '{print NF}' < sample.csv | uniq | wc -l
-> 1

タブ区切り、空白区切りの場合

タブ区切り(tsv)の場合は、ちょっとだけ工夫してあげる必要がある。 タブやスペース区切りの場合、空のカラムが存在しているとき、連続スペースを一つのデリミタとして 認識してしまうため、正しく数えることができない。

そういう場合は、sedコマンドで一度別の文字に置き換えてからawkに渡してやると、うまくいく。 ただし、デリミタにする文字がレコード中にあると、今度は誤検出されてしまうため、
出現する確率が限りなく低い文字(バッククオートとか)にしておきましょう。

$ sed -r 's/\t/``/g' < sample.csv | awk -F'``' {print NF"::"NR} | uniq | wc -l
-> 1

マウスもランチャーも使わず、キーボードだけでお気に入りのファイルを開く方法

目的

windowsの「ファイル名を指定して実行」機能を利用して、ランチャーっぽい動作を実現する。

動機

ふだんファイルを探すとき、マウスクリックを使ってCドライブからディレクトリをモジモジたどっていくのが煩わしくて嫌いなので、bluewindなどのランチャーソフトを使ってる

。。。のだが、まれにセキュリティルール等々でソフトウェアのダウンロード制限のある環境などではランチャーが使えないことがある

そんなとき、おとなしくマウスクリックを使って辿っていくのはなんか癪だし、普段慣れた動作ができないのはストレスがたまるので、ソフトウェアをダウンロードしないでランチャーっぽい動作ができるようにしたい

手順概略

1.ショートカットを配置しておくディレクトリを作る

2.上記のディレクトリにPATHを通す

3.立ち上げたいディレクトリや、ソフトウェアのショートカットを作成する

4.「ファイル名を指定して実行」機能を使ってショートカット名を指定する

検証OS

windows10 windows7

手順詳細

1.ショートカットを配置しておくディレクトリを作る

どこでもいいので、ショートカットを配置しておく用のディレクトリを作成する。(仮に、C:\Shortcuts とする) 以下、ここで作成したディレクトリを「ショートカットディレクトリ」と呼びます。

f:id:yamatatsu-blog:20170104205621j:plain

2.ショートカットディレクトリにPATHを通す

コンピュータ→プロパティ→システムの詳細設定→環境変数の設定から、PATH環境変数の末尾に、上記で作成した、C:\Shortcuts を追加します。 ※このとき、ショートカットディレクトリは、必ずPATH環境変数の末尾になるようにしてください。

f:id:yamatatsu-blog:20170104210848p:plain

3.立ち上げたいディレクトリや、ソフトウェアのショートカットを作成する

例えば、C:\project\document\phase1\sample という、それなりに階層の深いディレクトリに一発でたどり着きたいとする。(マウスクリックで到達するには、4回ぐらいクリックしなきゃいけない)

ショートカットディレクトリに、C:\project\document\phase1\sampleへのショートカットを作成します。このとき、ショートカット名を仮に、targetとします。

f:id:yamatatsu-blog:20170104211931p:plain

4.「ファイル名を指定して実行」機能を使ってショートカット名を指定する

3.の手順で作成したC:\ShortcutsディレクトリにPATHが通っているので、「ファイル名を指定して実行」機能で"target" と入力すれば、C:\Shortcuts\target.lnk が呼び出され、所望のディレクトリが一発で立ち上がります。

windowsキー + r を押して、「ファイル名を指定して実行」のウィンドウを立ち上げ、targetと入力してください。

f:id:yamatatsu-blog:20170104212113p:plain

応用編~特定のウェブサイトに一発で到達する~

ブラウザでインターネットの特定のページに到達するには、ちょっとひと手間が必要。 まず、テキストエディタで下記のようなcmdファイル(ggl.cmd)を作成してください。

start http://www.google.co.jp

これを同じようにショートカットディレクトリに保存し、「ファイル名を指定して実行」からgglと入力すれば、googleのトップページに到達できる。

注意点

ショートカットの名前にドットが入ると、うまく動作しません。 ショートカット名には、できる限りドットや記号を使わない方がよいです。