CSV ファイル内の列を削除するコマンド ライン コマンドはありますか?

CSV ファイル内の列を削除するコマンド ライン コマンドはありますか?

次の内容のファイルがあります:

1111,2222,3333,4444
aaaa,bbbb,cccc,dddd

元のファイルと同じだがn番目の列が欠けているファイルを取得したい。n = 2(または3)の場合

1111,2222,4444
aaaa,bbbb,dddd

または、n = 0(または1の場合もある)の場合

2222,3333,4444
bbbb,cccc,dddd

実際のファイルは数万の列を持ち、数ギガバイトにもなることがあります。

このような場合、いつものことながら、コマンドラインの魔術師がエレガントな解決策を提供してくれるのではないかと思います... :-)

実際のケースでは、最初の 2 列を削除する必要があります。これは、最初の列を 2 回連続して削除することで実行できますが、もう少し一般化するともっと面白くなると思います。

答え1

これは GNU coreutils からの切り取りに特有のものだと私は思います:

$ cut --complement -f 3 -d, inputfile
1111,2222,4444
aaaa,bbbb,dddd

通常、必要なフィールドは -f で指定しますが、--complement を追加すると当然意味が逆になります。'man cut' より:

--complement
    complement the set of selected bytes, characters or fields

注意点が 1 つあります。列のいずれかにカンマが含まれている場合、cut はスプレッドシートと同じ CSV パーサーではないため、cut は失敗します。多くのパーサーは、CSV 内のエスケープ カンマの処理方法についてさまざまな考え方を持っています。単純な CSV の場合、コマンド ラインでは、cut が依然として最適な方法です。

答え2

データが単純にコンマで区切られた列で構成されている場合:

cut -d , -f 1-2,4-

awk を使用することもできますが、フィールドをクリアするのは簡単ですが、区切り文字を削除するには多少の手間がかかるため、少し扱いに​​くいです。空のフィールドがない場合は、それほど難しくはありません。

awk -F , 'BEGIN {OFS=FS}  {$3=""; sub(",,", ","); print}'

実際のCSVでは、適切に引用符で囲めばフィールド内にカンマを表示できますが、実際のCSVライブラリ

答え3

CSV 対応ツールを使用して、ヘッダーのない CSV 入力ファイルから最初の 2 つの列を削除します。

$ cat file
1111,2222,3333,4444
aaaa,bbbb,cccc,dddd
$ mlr --csv -N cut -x -f 1,2 file
3333,4444
cccc,dddd

操作-xのオプションcutミラーmlr)は、操作を除外する名前付きフィールド (この場合は、フィールド番号 1 と 2)。CSV データにヘッダーがあれば、名前付きフィールドを使用できるようになります-f(-Nこのシナリオでは、オプションも削除する必要があります)。

Miller は CSV に対応しているため、埋め込まれたコンマ、引用符、改行を含む適切に引用符で囲まれたフィールドに対応します。

答え4

インデックスを使用して列を削除するには、以下のコマンドを試してください。

dropColumnCSV --index=0 --file=file.csv

これは、列がカンマで区切られている場合に機能します。sedコマンドは関数内で文字列を削除するために使用されます。

dropColumnCSV() {
  # argument check
  while [ $# -gt 0 ]; do
    case "$1" in
      --index=*)
        index="${1#*=}"
        ;;
      --file=*)
        file="${1#*=}"
        ;;
      *)
        printf "* Error: Invalid argument. *\n"
        return
    esac
    shift
  done

  # file check
  if [ ! -f $file ]; then
        printf "* Error: $file not found.*\n"
        return
  fi

  # sed remove command index zero
  if [[ $index == 0 ]]; then
    sed -i 's/\([^,]*\),\(.*\)/\2/' $file

  # sed remove command index greater than zero
  elif [[ $index > 0 ]]; then
    pos_str=$(for i in {1..$(seq "$index")}; do echo -n '[^,]*',; done| sed 's/,$//') ;
    sed -i 's/^\('$pos_str'\),[^,]*/\1/' $file
  fi
}

関連情報