次の内容のファイルがあります:
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
}