Bagaimana saya bisa melakukan hal berikut untuk file CSV menggunakan sed
atau awk
?
- Hapus kolom
- Gandakan kolom
- Pindahkan kolom
Saya memiliki meja besar dengan lebih dari 200 baris, dan saya tidak terlalu familiar sed
.
Bagaimana saya bisa melakukan hal berikut untuk file CSV menggunakan sed
atau awk
?
Saya memiliki meja besar dengan lebih dari 200 baris, dan saya tidak terlalu familiar sed
.
Jawaban:
Selain cara memotong dan menata ulang ladang (tercakup dalam jawaban lain), ada masalah bidang CSV yang unik.
Jika data Anda termasuk dalam kategori "aneh" ini, sedikit pemfilteran sebelum dan sesudah pemilahan dapat mengatasinya. Filter yang ditunjukkan di bawah memerlukan karakter \x01
, \x02
, \x03
, \x04
untuk tidak muncul di mana saja di data Anda.
Berikut adalah filter yang melilit tempat awk
pembuangan sederhana .
Catatan: bidang-lima memiliki tata letak "bidang kutip" yang tidak valid / tidak lengkap, tetapi tidak berbahaya di akhir baris (tergantung pada pengurai CSV). Tapi, tentu saja, hal itu akan menyebabkan hasil unexpedted bermasalah jika itu untuk ditukarkan jauh dari saat ini akhir-of-baris posisi.
Memperbarui; user121196 telah menunjukkan bug ketika koma mendahului kutipan trailing. Inilah solusinya.
Data
cat <<'EOF' >file
field one,"fie,ld,two",field"three","field,\",four","field,five
"15111 N. Hayden Rd., Ste 160,",""
EOF
Kode
sed -r 's/^/,/; s/\\"/\x01/g; s/,"([^"]*)"/,\x02\1\x03/g; s/,"/,\x02/; :MC; s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g; tMC; s/^,// ' file |
awk -F, '{ for(i=1; i<=NF; i++) printf "%s\n", $i; print NL}' |
sed -r 's/\x01/\\"/g; s/(\x02|\x03)/"/g; s/\x04/,/g'
Hasil:
field one
"fie,ld,two"
field"three"
"field,\",four"
"field,five
"15111 N. Hayden Rd., Ste 160,"
""
Berikut adalah filter pra , diperluas dengan komentar.
The pasca Filter hanya pembalikan \x01
. \x02
, \x03
,\x04
sed -r '
s/^/,/ # add a leading comma delimiter
s/\\"/\x01/g # obfuscate escaped quotation-mark (\")
s/,"([^"]*)"/,\x02\1\x03/g # obfuscate quotation-marks
s/,"/,\x02/ # when no trailing quote on last field
:MC # obfuscate commas embedded in quotes
s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g
tMC
s/^,// # remove spurious leading delimiter
'
Ini tergantung pada apakah file CSV Anda menggunakan koma hanya untuk pembatas, atau jika Anda memiliki kegilaan seperti:
bidang satu, "bidang, dua", bidang tiga
Ini mengasumsikan Anda menggunakan file CSV sederhana:
Anda dapat menyingkirkan satu kolom banyak cara; Saya menggunakan kolom 2 sebagai contoh. Cara termudah adalah menggunakan cut
, yang memungkinkan Anda menentukan pembatas -d
dan bidang mana yang ingin Anda cetak -f
; ini memerintahkannya untuk membagi koma dan bidang keluaran 1, dan bidang 3 sampai akhir:
$ cut -d, -f1,3- /path/to/your/file
Jika Anda benar-benar perlu menggunakan sed
, Anda dapat menulis ekspresi reguler yang cocok dengan n-1
bidang pertama , bidang n
th, dan sisanya, dan lewati menghasilkan n
th (di sini n
adalah 2, sehingga kelompok pertama adalah 1
waktu yang cocok:) \{1\}
:
$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file
Ada beberapa cara untuk melakukan ini awk
, tidak ada yang sangat elegan. Anda dapat menggunakan for
lingkaran, tetapi berurusan dengan koma yang tertinggal adalah hal yang menyakitkan; mengabaikan bahwa itu akan menjadi seperti:
$ awk -F, '{for(i=1; i<=NF; i++) if(i != 2) printf "%s,", $i; print NL}' /path/to/your/file
Saya merasa lebih mudah untuk menampilkan bidang 1 dan kemudian menggunakan substr
untuk melakukan semuanya setelah bidang 2:
$ awk -F, '{print $1 "," substr($0, length($1)+length($2)+3)}' /path/to/your/file
Ini menjengkelkan untuk kolom lebih jauh
Pada sed
dasarnya ini adalah ekspresi yang sama seperti sebelumnya, tetapi Anda juga menangkap kolom target dan memasukkan grup itu beberapa kali dalam penggantian:
$ sed 's/\(\([^,]\+,\)\{1\}\)\([^,]\+,\)\(.*\)/\1\3\3\4/' /path/to/your/file
Dalam awk
cara for loop itu akan menjadi sesuatu seperti (lagi-lagi mengabaikan tanda koma):
$ awk -F, '{
for(i=1; i<=NF; i++) {
if(i == 2) printf "%s,", $i;
printf "%s,", $i
}
print NL
}' /path/to/your/file
The substr
cara:
$ awk -F, '{print $1 "," $2 "," substr($0, length($1)+2)}' /path/to/your/file
(tcdyl datang dengan metode yang lebih baik dalam jawabannya )
Saya pikir sed
solusinya mengikuti secara alami dari yang lain, tetapi mulai menjadi sangat panjang
awk
adalah taruhan terbaik Anda. awk
mencetak bidang dengan nomor, jadi ...
awk 'BEGIN { FS=","; OFS=","; } {print $1,$2,$3}' file
Untuk menghapus kolom, jangan cetak:
awk 'BEGIN { FS=","; OFS=","; } {print $1,$3}' file
Untuk mengubah urutan:
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file
Arahkan ulang ke file output.
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file > output.file
awk
dapat memformat output juga.
Diberi file terbatas-ruang dalam format berikut:
1 2 3 4 5
Anda dapat menghapus bidang 2 dengan awk seperti:
awk '{ sub($2,""); print}' file
yang kembali
1 3 4 5
Ganti kolom 2 dengan kolom n jika perlu.
Untuk menduplikasi kolom 2,
awk '{ col = $2 " " $2; $2 = col; print }' file
yang kembali
1 2 2 3 4 5
Untuk mengganti kolom 2 dan 3,
awk '{temp = $2; $2 = $3; $3 = temp; print}'
yang kembali
1 3 2 4 5
awk umumnya sangat bagus dalam berurusan dengan konsep bidang . Jika Anda berurusan dengan CSV, dan bukan file yang dibatasi ruang, Anda dapat menggunakannya
awk -F,
untuk menentukan bidang Anda sebagai koma, bukan spasi (yang merupakan default). Ada sejumlah sumber daya awk online yang bagus, salah satunya saya cantumkan sebagai sumber di bawah ini.
Sumber untuk # 3
awk
, tetapi tampaknya menghasilkan ruang-dipisahkan bahkan jika pemisah lapangan (pemisah ,
lapangan hanya mengontrol bagaimana ia menangani input)
Ini akan berfungsi untuk menghapus
awk '{$2="";$0=$0;$1=$1}1'
Memasukkan
a b c d
Keluaran
a c d