GNU/Linux >> Linux の 問題 >  >> Linux

BashでCSVファイルを解析するには?

<ブロック引用>

Bash で CSV ファイルを解析する方法

この質問に遅れて、bashが新しい機能を提供するように、この質問はbashに関するものであり、すでに投稿された回答のどれも正確にこれを行うこの強力で準拠した方法を示していないためです .

bash の下の CSV ファイルを解析しています ロード可能モジュールを使用

RFC 4180 に準拠 、このサンプル CSV 行 のような文字列 :

12,22.45,"Hello, ""man"".","A, b.",42

として分割する必要があります

 1  12
 2  22.45
 3  Hello, "man".
 4  A, b.
 5  42

bash 読み込み可能 .C コンパイル済みモジュール。

bash では、ロード可能な C コンパイル モジュールを作成、編集、使用できます。 .読み込まれると、他のビルトインと同じように機能します !! (ソース ツリーで詳細を確認できます。;)

現在のソース ツリー (2021 年 10 月 15 日、bash V5.1-rc3) には多数のサンプルが含まれています:

accept        listen for and accept a remote network connection on a given port
asort         Sort arrays in-place
basename      Return non-directory portion of pathname.
cat           cat(1) replacement with no options - the way cat was intended.
csv           process one line of csv data and populate an indexed array.
dirname       Return directory portion of pathname.
fdflags       Change the flag associated with one of bash's open file descriptors.
finfo         Print file info.
head          Copy first part of files.
hello         Obligatory "Hello World" / sample loadable.
...
tee           Duplicate standard input.
template      Example template for loadable builtin.
truefalse     True and false builtins.
tty           Return terminal name.
uname         Print system information.
unlink        Remove a directory entry.
whoami        Print out username of current user.

完全に機能する cvs があります examples/loadables ですぐに使えるパーサー ディレクトリ:csv.c !!

Debian GNU/Linux ベースのシステムでは、

によって bash-builtins パッケージをインストールする必要がある場合があります。
apt install bash-builtins

ロード可能な bash-builtins の使用 :

次に:

enable -f /usr/lib/bash/csv csv

そこから、 csv を使用できます bash 組み込みとして .

私のサンプルでは:12,22.45,"Hello, ""man"".","A, b.",42

csv -a myArray '12,22.45,"Hello, ""man"".","A, b.",42'
printf "%s\n" "${myArray[@]}" | cat -n
     1      12
     2      22.45
     3      Hello, "man".
     4      A, b.
     5      42

次に、ループでファイルを処理します。

while IFS= read -r line;do
    csv -a aVar "$line"
    printf "First two columns are: [ '%s' - '%s' ]\n" "${aVar[0]}" "${aVar[1]}"
done <myfile.csv

この方法は明らかに、bash ビルトインの他の組み合わせや任意のバイナリへの fork を使用するよりも、最も速くて強力です。

残念ながら、システムの実装によっては、bash のバージョンが loadable なしでコンパイルされている場合 、これはうまくいかないかもしれません...

複数行の CSV フィールドを含む完全なサンプル

1 を含む小さなサンプル ファイルを次に示します。 見出し、4 列と 3 行。 2 つのフィールドに 改行 が含まれているため 、ファイルは 6 です 行の長さ。

Id,Name,Desc,Value
1234,Cpt1023,"Energy counter",34213
2343,Sns2123,"Temperatur sensor
to trigg for alarm",48.4
42,Eye1412,"Solar sensor ""Day /
Night""",12199.21

そして、このファイルを正しく解析できる小さなスクリプト:

#!/bin/bash

enable -f /usr/lib/bash/csv csv

file="sample.csv"
exec {FD}<"$file"

read -ru $FD line
csv -a headline "$line"
printf -v fieldfmt '%-8s: "%%q"\\n' "${headline[@]}"

while read -ru $FD line;do
    while csv -a row "$line" ; ((${#row[@]}<${#headline[@]})) ;do
        read -ru $FD sline || break
        line+=$'\n'"$sline"
    done
    printf "$fieldfmt\\n" "${row[@]}"
done

これはレンダリングされる可能性があります:(私は printf "%q" を使用しました 改行などの印刷できない文字を表す $'\n' として )

Id      : "1234"
Name    : "Cpt1023"
Desc    : "Energy\ counter"
Value   : "34213"

Id      : "2343"
Name    : "Sns2123"
Desc    : "$'Temperatur sensor\nto trigg for alarm'"
Value   : "48.4"

Id      : "42"
Name    : "Eye1412"
Desc    : "$'Solar sensor "Day /\nNight"'"
Value   : "12199.21"

そこには完全な作業サンプルがあります:csvsample.sh.txt orcsvsample.sh.

警告:

もちろん、これを使用した CSV の解析は完璧ではありません!これは多くの単純な CSV ファイルで機能しますが、エンコーディングとセキュリティに注意してください!!サンプルとして、このモジュールはバイナリ フィールドを処理できません!

csv.c ソースコードのコメントと RFC 4180 をよく読んでください!


引用符で囲まれた文字列を含み、say | で区切られた csv ファイルを解析できます。次のコードで

while read -r line
do
    field1=$(echo "$line" | awk -F'|' '{printf "%s", $1}' | tr -d '"')
    field2=$(echo "$line" | awk -F'|' '{printf "%s", $2}' | tr -d '"')

    echo "$field1 $field2"
done < "$csvFile"

awk 文字列フィールドを変数と tr に解析します 引用を削除します。

awk のように少し遅い フィールドごとに実行されます。


man から ページ:

<ブロック引用>

-d delimdelim の最初の文字は、改行ではなく、入力行を終了するために使用されます。

-d, を使用しています コンマで入力行を終了します。行の残りは読み取れません。そのため、$y は空です。


IFS を使用する必要があります -d の代わりに :

while IFS=, read -r col1 col2
do
    echo "I got:$col1|$col2"
done < myfile.csv

汎用の CSV 解析では、Bash だけでは処理できない問題の中でも特に、引用符で囲まれたフィールドにカンマを使用して処理できる特殊なツールを使用する必要があることに注意してください。そのようなツールの例は cvstool です と csvkit .


Linux
  1. Bashでファイルパスをどのように正規化しますか?

  2. Linux の Bash で syslog を確認するには?

  3. bash シェルでファイルのセクションを grep する方法

  1. VimでBashスクリプトを強調表示するには?

  2. Bashでファイルが空かどうかを確認するには?

  3. ファイルを bash シェル スクリプトに含める方法

  1. bashでファイルの絶対ディレクトリを取得するにはどうすればよいですか?

  2. ファイル内で \n を grep する方法

  3. Bashを使用してHTTPヘッダーを解析するには?