2 つの .csv ファイルがあります。最初のファイルには単語のリストがあります。 2 番目のファイルには 2 つの列があり、1 番目の列には最初のファイルのエントリと一致する値が含まれます。最初のファイルを1行ずつ読み、各行を使用して2番目のファイルをgrepしたいと思います。現在のコードを表示
- 行を読むとき
- する
- grep $line ./filetwo.csv
- <fileone.csv 完了
このコードは何も生成しません。 $line をファイルを読み込んで未割り当て変数に置き換えると完璧に動作します。私は長年この問題を研究してきましたが、一見簡単に見える質問に対する答えを見つけることができませんでした。 .csvファイルを読み取って、割り当てられた変数が直接割り当てられた変数と同じ結果を提供しない理由を理解できません。 zshシェルを使用しています。
答え1
CSVファイルはMicrosoftの世界でより一般的であるため、次のものがあります。
- ロケールの文字セットではなくUTF-16でエンコードされるため、変換が必要です。
- あるいは、UTF-8でエンコードされていますが、バイトオーダーマークがあります。
- CRLF 行区切り文字があります。
- 最後の行は分離されません(したがって
read
falseが返されます)。
これが真であることを確認できますfile yourfile.csv
。
これにより、次のことができます。
dos2unix < fileone.csv |
while IFS=, read -r first rest_if_any_ignored; do
dos2unix < filetwo.csv | grep -Fe "$first"
done
(正規表現マッチング-F
を実行するデフォルトではなく固定文字列検索に注意してください。)しかし、これは各行に対して3つのコマンドを実行し、各コマンドが毎回最初から内容を処理するため、かなり非効率的です。re
grep
fileone.csv
grep
filetwo.csv
$first
また、最初の列だけでなく、任意の場所で文字列を検索し、filetwo.csv
正確な一致を実行しません。たとえば、$first
isのfoo
場合とfoobar,other
行other,foobar
が報告されます。これはCSV参照も処理しません。したがって、適切なCSV解析機能を持つ言語を使用することをお勧めします。
これらのファイルに単純なCSV、つまり参照やヘッダーがない場合は、次の操作が行われますjoin
。
preprocess() {
dos2unix -O -- "$@" | sort -t, -k1b,1
}
join -t, <(preprocess < fileone.csv) <(preprocess < filetwo.csv)
ヘッダーと可能な引用符(改行を含むデータを含む)を持つ実際のCSVのmlr
場合は、CSVパーサーを使用できます。そのjoin
動詞。
foo
たとえば、最初の列がinfileone.csv
とbar
inで呼び出された場合filetwo.csv
:
mlr --csv join -j foo -r bar -f fileone.csv filetwo.csv
dos2unix
CRLF、無制限の行、およびBOMを持つUTF-8を処理できますが、UTF-16は処理できません。まず、UTF-8を使用するか、UTF-8に変換する必要がありますiconv
。
mlr
単純なCSVや他のいくつかのテーブル形式も実行できます。詳細については、該当するマニュアルを参照してください。