LoginSignup
54
53

More than 5 years have passed since last update.

巨大なファイルをシェルスクリプトで読む時

Last updated at Posted at 2014-10-30

巨大なファイルをシェルスクリプトで読む時

ちょっと2000万行くらいのcsvを読む機会があって、その時の小ネタ。

注釈追記)
コメントでも書いたんですけど、コマンド置換で cat でファイル開いて for に食わせるよりも、
1行ずつ処理するのは while read の方が一般的みたいです。

なんか注釈追記したら非常に実の無い記事になってしまったw

中身は

こんな感じのが2000万行くらいずらずら続いてる感じ。

items.txt
"item_id","title","description","price","url","image_url"
"11111","たいとる","でぃすくりぷしょん","1000","http://example.com/item/11111","http://example.com/11111.jpg"
"22222","たいとる2","でぃすくりぷしょん2","2000","http://example.com/item/22222","http://example.com/22222.jpg"

1行ずつ処理するとき

駄目なやつ

コマンド置換

  • `cat items.txt`
  • $(cat items.txt)

だと、いったん全部ファイルの中身展開してから処理に流れるので、ちょっとまずい事になる。
これはコマンド置換のせいなので cat に限らず head とか tail とかでも同じ。

駄目
for x in `cat items.txt`; do
    echo $x
done;

大丈夫なやつ

read で1行ずつ読むのが正解。

おk
while read x; do
    echo $x
done < items.txt

これでもおk。

おk2
cat items.txt | while read x; do
    echo $x
done

余談

コレを

  • ダブルクォートを消して
  • tsvに変換

したので、自分用メモも兼ねてついでにそれも。

bash
#!/bin/bash

# とりあえずヘッダはstderrに吐いておこうかな
head -n 1 items.txt >&2

while read x; do
    echo $x | awk '
BEGIN {
    FS = ","      # 入力フィールドセパレータ
    OFS = "\t"    # 出力フィールドセパレータ
}
{
    # 各フィールドを囲ってる前後のダブルクォートを除去
    for(i=1; i<=NF; ++i) {
        sub("^\"", "", $i);
        sub("\"$", "", $i);
    }

    print $0    # OFS に ¥t 指定してるのでコレでおk
}'
done < <(tail -n +2 items.txt)    # 1行目はヘッダなので除外
54
53
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
53