Aşağıdakileri sedveya kullanarak bir CSV dosyasına nasıl yapabilirim awk?
- Bir sütunu sil
- Bir sütunu çoğalt
- Bir sütunu taşı
200'den fazla satırdan oluşan büyük bir masam var ve o kadar aşina değilim sed.
Aşağıdakileri sedveya kullanarak bir CSV dosyasına nasıl yapabilirim awk?
200'den fazla satırdan oluşan büyük bir masam var ve o kadar aşina değilim sed.
Yanıtlar:
Alanların nasıl kesileceği ve yeniden düzenleneceği (diğer cevaplarda ele alınan) bir yana, ilginç CSV alanları da var.
Verileriniz bu "ilginç" kategoriye girerse, bir miktar ön ve son filtreleme bununla ilgilenebilir. Aşağıda gösterilen filtreler karakterler gerektiren \x01, \x02, \x03, \x04verilerinizin herhangi bir yerinde görünmemesine.
İşte basit bir awkçöplük etrafına sarılı filtreler .
Not: Beşinci alanın geçersiz / eksik "alıntı alanı" düzeni var, ancak satırın sonunda (CSV ayrıştırıcısına bağlı olarak) iyi huylu. Ancak, elbette, şu anki satır sonundan uzağa kaydırılırsa , sorunlu, beklenmeyen sonuçlara yol açacaktır .
Güncelleştirme; user121196 , virgül sondaki bir alıntıdan önce geldiğinde bir hata olduğunu belirtti. İşte düzeltme.
Veri
cat <<'EOF' >file
field one,"fie,ld,two",field"three","field,\",four","field,five
"15111 N. Hayden Rd., Ste 160,",""
EOF
Kod
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'
Çıktı:
field one
"fie,ld,two"
field"three"
"field,\",four"
"field,five
"15111 N. Hayden Rd., Ste 160,"
""
İşte yorumlar ile genişletilmiş ön filtre . Sonrası filtre sadece bir ters olan . , ,\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
'
Bu, CSV dosyanızın yalnızca sınırlayıcılar için virgül kullanıp kullanmadığına veya deliliğinizin olup olmamasına bağlıdır:
alan bir, "alan, iki", alan üç
Bu, basit bir CSV dosyası kullandığınızı varsayar:
Tek bir sütundan kurtulmanın birçok yolu vardır; Sütun 2'yi örnek olarak kullandım. En kolay yol muhtemelen kullanmaktır cut, bu da bir sınırlayıcı -dve hangi alanları yazdırmak istediğinizi belirtmenizi sağlar -f; bu, virgüllere ve çıkış alanına 1 ve sonuna kadar alanları 3'e bölmesini söyler:
$ cut -d, -f1,3- /path/to/your/file
Gerçekten kullanmanız sedgerekirse, ilk n-1alanlarla, nth alanıyla ve kalanıyla eşleşen normal bir ifade yazabilir ve th çıktısını atlayabilirsiniz n(burada n2, yani ilk grup eşleşen 1zamandır \{1\}):
$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file
Bunu yapmanın çeşitli yolları var awk, hiçbiri özellikle şık değil. Bir fordöngü kullanabilirsiniz , ancak takip eden virgülle uğraşmak acı vericidir; böyle bir şey olacağını görmezden gelmek:
$ awk -F, '{for(i=1; i<=NF; i++) if(i != 2) printf "%s,", $i; print NL}' /path/to/your/file
Alan 1'i çıkarmayı daha kolay buluyorum ve ardından substralan 2'den sonra her şeyi çıkarmak için kullanıyorum :
$ awk -F, '{print $1 "," substr($0, length($1)+length($2)+3)}' /path/to/your/file
Bu olsa boyunca boyunca daha da sütunlar için can sıkıcı bir durum
Bu sedesasen öncekiyle aynı ifadedir, ancak aynı zamanda hedef sütunu yakalar ve yerine geçen grubu birkaç kez eklersiniz:
$ sed 's/\(\([^,]\+,\)\{1\}\)\([^,]\+,\)\(.*\)/\1\3\3\4/' /path/to/your/file
In awkiçin döngü yolu o (yine sondaki virgül görmezden) gibi bir şey olurdu:
$ awk -F, '{
for(i=1; i<=NF; i++) {
if(i == 2) printf "%s,", $i;
printf "%s,", $i
}
print NL
}' /path/to/your/file
substryol:
$ awk -F, '{print $1 "," $2 "," substr($0, length($1)+2)}' /path/to/your/file
(tcdyl daha iyi yöntem ile geldi onun cevabını )
Bence sedçözüm diğerlerinden doğal olarak geliyor ama saçma sapmaya başladı
awkEn iyi bahis awkalanları sayıya göre yazdırır, bu yüzden ...
awk 'BEGIN { FS=","; OFS=","; } {print $1,$2,$3}' file
Bir sütunu kaldırmak için yazdırmayın:
awk 'BEGIN { FS=","; OFS=","; } {print $1,$3}' file
Siparişi değiştirmek için:
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file
Bir çıktı dosyasına tekrar yönlendirin.
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file > output.file
awk çıkışı da biçimlendirebilir.
Boşlukla ayrılmış bir dosyaya aşağıdaki biçimde verilir:
1 2 3 4 5
Alan 2'yi awk ile kaldırabilirsiniz:
awk '{ sub($2,""); print}' file
hangi döner
1 3 4 5
Uygunsa, sütun 2'yi sütun n ile değiştirin.
2. sütunu çoğaltmak için,
awk '{ col = $2 " " $2; $2 = col; print }' file
hangi döner
1 2 2 3 4 5
2. ve 3. sütunları değiştirmek için,
awk '{temp = $2; $2 = $3; $3 = temp; print}'
hangi döner
1 3 2 4 5
awk genellikle kavramı ile ilgili çok iyi olduğunu alanları . Bir CSV ile uğraşıyorsunuz ve boşlukla ayrılmış bir dosya değil, sadece
awk -F,
alanınızı boşluk yerine virgül olarak tanımlamak için (varsayılan ayardır). Çevrimiçi olarak bir tanesi aşağıda kaynak olarak listelediğim birkaç iyi awk kaynağı var.
# 3 kaynağı
awk, ancak alan ayırıcı olsa bile alandan ayrılmış çıktılar veriyor ,(alan ayırıcı sadece girdilerin nasıl işlendiğini kontrol ediyor)
Bu silmek için çalışacak
awk '{$2="";$0=$0;$1=$1}1'
Giriş
a b c d
Çıktı
a c d