Awk kullanarak sütunları yeniden düzenleme


13

Kullanarak csv dosyamın 7. sütun sonuna taşımak için çalışıyorum

awk -F '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}',OFS= "$file"

burada $ dosyası bir dizindeki bir .csv dosyasıdır. Ancak, çıktı

awk:                          ^ syntax error

Herkes bu hatayı nasıl düzeltebileceğini biliyor mu?


7
Awk hatalarını gösterirken, her şeyi göstermeniz gerekir. ^Hata ile karşılaşıldı komutların özel bölümünü gösterir.
terdon

Yanıtlar:


11

-FSeçenek bir argüman gerekir: -F,örneğin.

awkKomut dosyasının sonu , parametrelerin geri kalanıyla birlikte bir (boşluk karakteri) ile ayrılmalıdır .

Alan ayırıcı ise ,ve bunu korumak istiyorsanız ve sütun sayısı sabit ve 11'e eşit veya daha düşükse, şunu deneyin:

awk -F, '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' OFS=, "$file"

8
@anuribs çok az program buna izin verir. Standart yol command file > newfile && mv newfile file. Yani GNU yeni bir sürümü söyledi awkbunu desteklemek için: gawk -i inplace '{blah blah}' file.
terdon

1
alternatif olarak, yerine mv newfile filekullanabilirsiniz cat newfile > file ; rm -f newfile- bu inode ve izinlerini korur file.
cas

ve mktempgeçici dosya adlarını komut dosyalarına kodlamak yerine kullanmak genellikle iyi bir fikirdir . örneğintf=$(mktemp) ; command file > "$tf" ; cat "$tf" > file ; rm -f "$tf"
cas

8

Daha kısa çözüm

awk -F',+' -v OFS=, '{$(NF+1)=$7; $7=""; $0=$0; $1=$1}1' file

,+Tüm awksürümlerde çalışıp çalışmayacağından emin değilim , ancak en azından GNU -cawk'de , aynı zamanda uyumluluk modunda çalışıyor.

Açıklama:

  • $(NF+1)=$7: önce satırın sonuna 7. alan ekliyoruz ( $12=$7bu durumda olabilir)
  • $7="": sonraki adımda 7. alan silinir (ancak çevresindeki sınırlayıcılar kalır)
  • sınırlayıcıları kaldırmak için $0=$0birden çok virgülün alan ayırıcısı olarak ele alındığı tüm kaydı (yoluyla ) yeniden ayarlamamız gerekir (bu -F',+', burada +bir veya daha fazla kez yapılır) ve ayrıca $1=$1önceden ayarlanmış çıktı alanını kullanarak satırı yeniden oluşturmaya zorlamak için geçerli kaydı yeniden düzenlememiz gerekir. ayırıcı (bir seçenekle ayarlanır -v OFS=,)
  • tüm karıştırma tamamlandıktan sonra sonucu yazdırmaya hazırız 1

Örnek girdi:

1,2,3,4,5,6,7,8,9,10,11

çıktı

1,2,3,4,5,6,8,9,10,11,7

Diğer sütunlar boşsa ne olur? Ancak, evet, FS POSIX'te düzenli bir ifadedir (birden fazla karakter ise), bu yüzden ,+çalışmalıdır.
Random832

(1) Giriş verilerinin yedinci sütununu "null" değil ve sadece null değerine ayarlamak değil, bu sorunun zor bir parçası olduğunu anlıyorum. Ancak, Random832'nin dediği gibi, çözümünüz boş sütunları tıkar (örneğin, all,ball,call,,,fallall,ball,call,fall). (2)  $(NF+1)=$7akıllı bir yaklaşımdır. IMHO, $0 = $0 OFS $7biraz daha net, sadece birkaç karakter daha uzun ve aynı şeyi yapıyor gibi görünüyor. Kodunuzla $0 = $0 OFS $7aynı şeyi yapmayan bir durum düşünebiliyor musunuz?
G-Man,

@ Random832 @ G-Man evet, boş alanlar, boş satırlar veya NF <7 gibi bazı kenar durumlarda ayrı ayrı ele alınmalı veya kod yeniden düzenlenmelidir. Bu sadece bir fikirdir, tüm genel durumlar için “tam çözüm” değil, açık olmalıdır. $0=$0 OFS $7büyük olasılıkla aynıdır $(NF+1)=$7, ancak genel olarak değil, yalnızca kodun geri kalanında değişiklik olmaz.
jimmij

5

OFS=Alanlarla ayırıcı olmadan yazdırıyorsanız , $7bir değişkenin değerini kolayca kaydedebilir, $7boş olarak ayarlayabilir ve çizgiyi ve değişkeni doğrudan yazdırabilirsiniz. Tüm alanları belirtmenize gerek yoktur:

$ cat file
1,2,3,4,5,6,7,8
$ awk -F, -vOFS= '{k=$7; $7=""; print $0,k}' file 
12345687


3

Özellikle awk kullanmak istediğinizi söylemediniz ve tarafından sağlanan düzenlemeyi kullanmak istediğinizi söylediniz sed -i, işte bir sed -ivaryant. Genellikle awksütunlarla çalışmak için daha iyidir, ancak bu tercih ettiğim bir durumdur sed, çünkü doğal olarak rasgele sayıda sütun işler.

MOVECOL=7
N=$((MOVECOL-1))
sed -r -e "s/^(([^,]*,){$N})([^,]*),(.*)/\1\4,\3/" -i test.csv

Açıklama:

  • -r genişletilmiş normal ifadeleri seçer, böylece çok fazla ters eğik çizgiden kaçınırız
  • ilk grup, virgülle sonlandırılmış dizelerin $ N tekrarı, başka bir deyişle, taşımak istediğimizden önceki sütunlar, son bir virgülle
  • ikinci grup $ N-th tekrarı, bunu unutuyoruz
  • üçüncü grup, son virgül olmadan taşımak istediğimiz sütundur
  • dördüncü grup daha önce virgül kullanmadan taşımak istediğimiz sütundan sonraki tüm sütunlardan oluşur
  • ilk grup, son grup ve çıkardığımız sütunla değiştiririz, gerekirse virgül ekleriz.

Tabii ki bu, virgülleri tırnak içinde saklayan (veya daha da kötüsü, onlardan kaçan) dosyalarla çalışmaz, ancak awk bazı ciddi akrobasi olmadan da bunu yapmaz. Eğer böyle bir sorun varsa birlikte daha iyi olurdu perlmodülü Text:CSVveya pythonmodül csv.


2

Birkaç awkvaryant (dosyanızın değişkenin içinde olduğu varsayılarak $file)

  • Burada tüm sütunlar için döngü yapabilir, alan ayırıcısı (OFS) ile yazdırabilir ve satır sonundaki kayıt sonlandırıcıyı (ORS) yazdırabilirsiniz.

    awk  -F',' -v OFS=,                                \
    '{for(i=1;i<=NF;i++) if (i!=7) printf "%s",$i OFS; \
    printf "%s",$7;printf ORS}' "$file"
    
  • Burada bir normal ifade ve gensub()işlev kullanarak

    gawk -F',+' -v OFS=, '{$0=gensub(/\s*\S+/,"",7) OFS $7}1' "$file"

    öldürme 7 inci alanını ve satırın sonunda yazdırmadan.

    • $0 tüm kayıt
    • $nn inci rekor
    • NF geçerli satırın Alan Sayısıdır
    • OFS çıktı dosyalanmış ayırıcı
    • ORS çıkış kayıt sonlandırıcısı
    • 1awk trueve default ( $0) yazdırmak için söyleyecek hiledir .

Güncelleme ...

Neredeyse 7'den aşağıdaki tüm sütunları kayması mümkündür, unutmak inci biri.

awk  -F',' -v OFS=, '{tmp=$7; for(i=7;i<=NF;i++) $i=$(i+1); $NF=tmp}1 ' "$file"

(1) Muhtemelen, OFS $7daha sağlam olurdu "," $7. (2) ", " $7Sorunun OP'nin virgüllerden sonra boşluk istemediğini belirttiği sürece bunun yanlış olduğuna inanıyorum . (Ve, giriş verilerinde virgüllerden sonra boşluklar $7olsaydı, zaten bir boşlukla başlayacaktı ve fazladan bir tane ekleyecektin.)
G-Man 'Yeniden Monica'yı Geri Yükle'

@ G-Man Esas olarak bazı fikirler, bazı varyantlar önermekti. Teşekkürler, nokta için, OFS $7sadece daha sağlam değil, daha da genel ( "acele atık yapar" )
Hastur
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.