7つの代わりに6つのフィールドを持つレコードを含むファイルに追加フィールドを追加する

7つの代わりに6つのフィールドを持つレコードを含むファイルに追加フィールドを追加する

カンマ区切りのテキストファイルに問題があります。混合レイアウト(数百)のファイルの受信を開始しようとすると、一部のレコードには7つのフィールド(合計6つのカンマ)があり、同じファイル内の他のレコードには6つのフィールド(5つのカンマ)があります。銃)。

5つのカンマを含むレコードを見つけたら、レコードの最後にカンマを追加してNAを追加して、ロードプロセスで最後のNAである7つのフィールドがあると思うようにしたいと思います。

これが私が今持っているものです。最初のレコードには7つのフィールドがあり、2番目のレコードには6つしかありません。

200000003183000100,Data,NA,0,IN,0,0.00
200000004625000000,Data,NA,0,IN,0

これが私が期待したものです(両方のレコードに7つのフィールドがあります)。

200000003183000100,Data,NA,0,IN,0,0.00
200000004625000000,Data,NA,0,IN,0,NA

sed やこれに似たものでカンマを数え、カンマが 5 つだけあるたびにファイルの末尾に、NA を追加すればよい。これは何百ものファイルで発生するため、ファイル名をパラメータとして使用するのか、それと同様のものを使用するのかは不明です。

答え1

もし許可される:

awk -F, 'NF==6{$0=$0",NA"}1' file

答え2

〜のようにGil Quinaultの回答しかし、現在の行の末尾に文字列の代わりに新しいフィールドとして新しいフィールドを追加します。コマンドラインで区切り文字と予想されるフィールドの数を設定することもでき、不足しているフィールドは文字列で埋められますNA

$ awk -F , -v nf=7 'BEGIN { OFS = FS } { for (i = NF+1; i <= nf; ++i ) $i = "NA" }; 1' file
200000003183000100,Data,NA,0,IN,0,0.00
200000004625000000,Data,NA,0,IN,0,NA
$ awk -F , -v nf=12 'BEGIN { OFS = FS } { for (i = NF+1; i <= nf; ++i ) $i = "NA" }; 1' file
200000003183000100,Data,NA,0,IN,0,0.00,NA,NA,NA,NA,NA
200000004625000000,Data,NA,0,IN,0,NA,NA,NA,NA,NA,NA

これは明らかに入力が次のようになると仮定します。シンプルなCSV形式(挿入されたカンマや改行を含まないフィールド)

答え3

awkの効率を高めるために必要な場合を除き、レコード($0)やフィールド($1など)を変更しないでください。$2これはそれらのどれも変更しません。

awk -F, '{print $0 (NF==6 ? ",NA" : "")}'

他の既存のawk回答は$ 0を変更するかフィールドを変更しますが、どちらも処理速度が遅くなります。

これは$ 0を直接変更します(したがって間接的にフィールドを追加します)。

awk -F, 'NF==6{$0=$0",NA"}1'
awk '/(.*,){6}/ || sub(/$/,",NA")'
awk '!/(.*,){6}/{$0=$0",NA"}1'

これを行うには、awkがサイズが増加するにつれて移動する新しいメモリを見つける必要があります$0(変数のサイズをリンクまたは変更することはawkで最も遅い操作の1つです)、awkがフィールドに再分割されるように$0します。

これはフィールドを直接変更します(したがって$ 0間接的に)。

awk -F, -v nf=7 'BEGIN { OFS = FS } (NF < nf){ $(nf)="N/A"}1'
awk -F, -v nf=7 'BEGIN { OFS = FS } { for (i = NF+1; i <= nf; ++i ) $i = "NA" }; 1'

これにより、awk はそのフィールドで再構築され、サイズの増加により移動する$0新しいメモリを見つけるには awk が再び必要になります。$0

GNU awkを使用して何百もの(ARG_MAX未満)CSVファイルに対してawkスクリプトを実行するには、次の手順を実行します。

awk -i inplace 'script' file*.csv

または awk を使用してください。

tmp=$(mktemp)
for file in file*.csv; do
    awk 'script' "$file" > "$tmp" &&
    mv -- "$tmp" "$file"
done

答え4

Posix sed、6番目のコンマを変更しようとし、成功すると印刷して次のレコードを読み取る(テストコマンドティー) それ以外の場合は、,NA現在のレコードの末尾に文字列を追加します。

sed '
  s/,/,/6;t
  s/$/,NA/
' file

を使用するawk1つの方法は次のとおりです。

awk '/(.*,){6}/ || sub(/$/,",NA")' file

複数のファイルに対してこれを行う必要がある場合は、コマンドを使用することがありますfind

CSVファイルの名前が指定されたとします。*.csv

find . -type f -name '*.csv' -exec \
  sed -i 's/,/,/6;t' -e 's/$/,NA' {} +

awkの場合、awkがサポートしている場合はinplaceオプションを使用してください(GNU awkバージョン4.1.0以降)

find . -type f -name "*.csv" -exec \
awk -i inplace '!/(.*,){6}/{$0=$0",NA"}1' {} +

シンボル{}+複数のファイル名をawkまたはsedコマンドラインに関連付けて、これらのユーティリティへの呼び出しを最小限に抑えます。

メモ:

  • ファイルには5つまたは6つのカンマがあります。
  • フィールド自体にカンマを含めることはできません。
  • 行末はLinuxスタイルです(\ n)。

関連情報