web-dev-qa-db-ja.com

CSVファイルの複数の行を削除します

私はこの割り当てに取り組んでおり、異なる顧客のCSVファイルから行を削除しています。このコードを使用して特定の顧客を削除する方法を見つけました。

delete() {
  awk -F "\"*;\"*" '$1 != '$@' {print $ALL}' input.csv > output.csv
}

delete $@

ただし、複数の顧客を同時に削除する必要があります。 csvファイルの最初の列に格納されている顧客番号で顧客を識別できます。異なる顧客番号用の配列を作成し、配列をループするためのwhileループを作成することになっていますが、それを理解することはできません。

1
Lotte

なぜこれをシェル関数でラップするのかわかりません-それがあなたの割り当ての要件だと思います。

最初に、"*;"*をAwkのフィールド区切り文字として使用することは、引用符で囲まれたCSVフィールドを処理する堅牢な方法ではないことに注意してください。たとえば、行の最初のフィールドまたは最後のフィールドが引用符で囲まれていると失敗し、 t引用符で区切られた区切り文字(つまり、実際に;を含む引用符で囲まれたフィールド)を保持します。これにより、CSVフィールドを引用する全体のポイントが失われます。

第二に、シェル変数(または位置パラメーター)をそのようにAwk式に渡さないでください。正しい方法は、それらをエクスポートしてからENVIRON配列を介してアクセスするか、コマンドラインオプション-v。したがって、「単一顧客」の実装はより適切に記述されます。

delcust() {
  awk -F '"*;"*' -v cust="$1" '$1 != cust' input.csv > output.csv
}
delcust "$1"

couldこれを変更して複数の定位置パラメーターを渡しますが、標準入力を介して顧客リストを渡し、値のファイルとして解析することをお勧めします。そのようにして、連想配列(またはハッシュ)に基づいて標準的なAwkルックアップを行うことができます。

delcusts() {
  printf '%s\n' "$@" | awk -F'"*;"*' 'NR==FNR {custs[$0]=1; next} !($1 in custs)' - input.csv > output.csv
}
delcusts "$@"

ルールがゼロ以外を評価する場合、printがデフォルトのアクションであるため、Awkで明示的なprintを必要としないことに注意してください。

2
steeldriver

配列は本当に必要ありません。次のように関数を定義できます。

delete() {
  awk -v customer="^($1)\$" -F ";" '$1 !~ customer {print $ALL}' input.csv >output.csv 
}

フィールドセパレータの定義方法がわかりませんでしたので、テストできるように変更しました。関連する部分は、否定された正規表現!~を使用することです。また、awkの-vパラメータを使用して、シェルを引用する多くの頭痛からあなたを救うことができます。

これにより、次のようなパラメーターを使用して複数の顧客を削除できます。

delete 'bla|foo'

Input.csvの場合:

bla;blu;bli
foo;faa;fii
blafoo;blufaa;blifii

それはもたらすだろう

blafoo;blufaa;blifii

output.csvで。

本当に配列を使用したい場合は、上記のdelete()関数で使用する配列を準備する小さなヘルパー関数をさらに定義できます。

join() { local IFS=\|; echo "$*"; }

これにより、bash配列を定義し、正規表現の代替構文に変換できます。

$ a=(bla blu)
$ join ${a[@]}
bla|blu

次に、次のようにdelete()を呼び出すことができます。

$ a=(customer1 customer2)
$ delete "$(join ${a[@]})"

(zshユーザー向けの小さなメモ:join()関数はzshには必要ありません。次のパラメーター展開を使用するだけで済みます:${(j:|:)a}すべての配列要素を|文字で結合します)

0
Sebastian Stark