İlk alan dışında her şeyi awk ile yazdırma


108

Şuna benzeyen bir dosyam var:

AE  United Arab Emirates
AG  Antigua & Barbuda
AN  Netherlands Antilles
AS  American Samoa
BA  Bosnia and Herzegovina
BF  Burkina Faso
BN  Brunei Darussalam

Ve sırayı ters çevirmek istiyorum, önce 1 $ ve ardından 1 $ dışında her şeyi yazdırmak istiyorum:

United Arab Emirates AE

"Alan 1 hariç her şey" numarasını nasıl yapabilirim?


2
Merhaba @cfisher, fazladan boşluk olmadan döngü açısı olmadan yapılabilir.
Juan Diego Godoy Robles

Yanıtlar:


91

Atama $1işe yarıyor ama önde gelen bir boşluk bırakacakawk '{first = $1; $1 = ""; print $0, first; }'

Ayrıca, sütunların sayısını bulabilir NFve bunu bir döngüde kullanabilirsiniz.


2
Tamamen tembeller için; işte klashxx 'kodu .
Serge Stroobandt

1
Harika. Sed ile önde gelen boşluktan kurtuldum: awk {'first = $1; $1=""; print $0'}|sed 's/^ //g'
Thyag

Normal modda 'Ctrl + V Gd' ye basarak VIM ile boşluk kolayca kaldırılır
Santi

107

$1=""Ben Jackson'ın bahsettiği gibi bir boşluk bırakır, bu yüzden bir fordöngü kullanın :

awk '{for (i=2; i<=NF; i++) print $i}' filename

Dolayısıyla, dizeniz "bir iki üç" ise, çıktı şöyle olacaktır:

iki
üç

Sonucun tek satırda olmasını istiyorsanız, aşağıdakileri yapabilirsiniz:

awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}' filename

Bu size "iki üç" verecek


4
ve ekstra bir son boşluk
NeronLeVelu

2
kullanmak daha iyi: awk '{for(i=2;i<=NF;i++){ printf("%s",( (i>2) ? OFS : "" ) $i) } ; print ;}' hangisi: alanları 2'yi NF'ye yazdırın, Çıktı Alanı Ayırıcısını gerektiği gibi ekleyin (yani, 2 $ 'dan öncekiler hariç). Son baskı, geçerli satır yazdırmayı bitirmek için son bir satırsonu ekler. FS / OFS'yi değiştirirseniz işe yarayacak (yani, her zaman "boşluk" olmayacak)
Olivier Dulac

İkincisi benim için çok iyi çalıştı. İlki, o kadar değil. Neden olduğundan emin değilim. Tüm metni parçaladı.
sesler

72

Kullanım cutile komutu --complementseçeneği:

$ echo a b c | cut -f 1 -d ' '
a
$ echo a b c | cut -f 1,2 -d ' '
a b
$ echo a b c | cut -f 1 -d ' ' --complement
b c

2
Awk'a özgü soruyu yanıtlamamakla birlikte, awk yinelenen boşlukları kaldırdığı için bunu en kullanışlı buldum ve kesme işlemi yapmıyor.
Fmstrat

19
echo a b c | cut -d' ' -f 2- bir alternatif
Luis

2
Nice - @Luis çözümü, --complement'i desteklemeyen Mac'te çalışıyor
metadaddy

21

Belki de en kısa yol:

$ awk '{$(NF+1)=$1;$1=""}sub(FS,"")' infile
United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

Açıklama:

$(NF+1)=$1: "Yeni" bir son alanın üreticisi.

$1="": Orijinal ilk alanı boş olarak ayarlayın

sub(FS,""): İlk iki işlemden sonra {$(NF+1)=$1;$1=""}alt kullanarak ilk alan ayırıcısından kurtulun. Son baskı örtüktür.


13
awk '{sub($1 FS,"")}7' YourFile

İlk alanı ve ayırıcıyı kaldırın ve sonucu yazdırın ( 7sıfır olmayan bir değerdir, bu nedenle 0 $ yazdırılır).


En iyi cevap! Upvoted. Sadece kullanmaktan farkı 1nedir? Bu kalıbın kullanımını merak ediyorum ve bunu anlamak istedim. Teşekkürler!
Abhijeet Rastogi

10
awk '{ saved = $1; $1 = ""; print substr($0, 2), saved }'

İlk alanı , başlangıcında ""tek bir kopya bırakacak şekilde ayarlamak . Bunun yalnızca tek bir karakter olduğunu varsayarsak (varsayılan olarak, tek boşluktur), ile kaldırabiliriz . Ardından kaydedilmiş kopyasını ekleriz .OFS$0OFSsubstr($0, 2)$1


6

Perl çözümüne açıksanız ...

perl -lane 'print join " ",@F[1..$#F,0]' file

tek boşluğun giriş / çıkış ayırıcısı ile basit bir çözümdür ve şunları sağlar:

United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

Sıradaki bu biraz daha karmaşık

perl -F`  ` -lane 'print join "  ",@F[1..$#F,0]' file

ve giriş / çıkış ayırıcısının iki boşluk olduğunu varsayar:

United Arab Emirates  AE
Antigua & Barbuda  AG
Netherlands Antilles  AN
American Samoa  AS
Bosnia and Herzegovina  BA
Burkina Faso  BF
Brunei Darussalam  BN

Bu komut satırı seçenekleri kullanılır:

  • -n girdi dosyasının her satırında döngü yapın, her satırı otomatik olarak yazdırmayın

  • -l işlemeden önce yeni satırları kaldırır ve daha sonra tekrar ekler

  • -aotomatik bölme modu - giriş satırlarını @F dizisine ayırın. Beyaz boşlukta bölmeye varsayılanlar

  • -F autosplit değiştirici, bu örnekte '' (iki boşluk)

  • -e aşağıdaki perl kodunu çalıştırın

@Fher satırdaki kelime dizisidir, 0'dan başlayarak dizine
$#Falınır, içindeki kelimelerin sayısı, @F
@F[1..$#F]1. öğeden son öğeye kadar
@F[1..$#F,0]olan bir dizi dilimidir, son öğeden son öğeye kadar öğe 1'in bir dizi dilimi ve 0 öğesidir


1
Çalıştırdım ve sonunda fazladan bir numara vardı, bu yüzden bu sürümü kullandım: perl -lane 'shift @F; print join "", @F '
Hans Poo

2

Gawk'daki alan ayırıcı (en azından) bir karakter olabileceği gibi bir karakter de olabilir (aynı zamanda bir normal ifade de olabilir). Verileriniz tutarlıysa, bu işe yarayacaktır:

awk -F "  " '{print $2,$1}' inputfile

Çift tırnak arasındaki iki boşluk.


Eldeki durum için en iyi cevap, ancak teknik olarak bu, ilk alan dışında her şeyin nasıl yazdırılacağı sorusuna cevap vermiyor.
Dan Molding

@DanMoulding: Dosya ülke kodunu ayırmak için iki boşluk kullanımında tutarlı olduğu sürece ve iki boşluk başka olaylar birbirine vardır, cevabım yok adresini soru.
sonraki duyuruya kadar duraklatıldı.

2
Bu soruya gelen insanlar buraya gelirler çünkü ilk alan hariç her şeyi nasıl yazdıracaklarını bilmek isterler (soru başlığına bakın). Ben buraya böyle inmiştim. Cevabınız, birinci alanın ardından ikinci alanın nasıl yazdırılacağını gösterir. Bu muhtemelen OP'nin özel durumu için en iyi çözüm olsa da, ilk alan dışında her şeyin nasıl yazdırılacağına dair genel sorunu çözmez.
Dan Molding

2

awk '{ tmp = $1; sub(/^[^ ]+ +/, ""); print $0, tmp }'


2

Tüm kayıtları bir sonrakine taşıyalım ve sonuncuyu ilk olarak ayarlayalım:

$ awk '{a=$1; for (i=2; i<=NF; i++) $(i-1)=$i; $NF=a}1' file
United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

açıklama

  • a=$1 ilk değeri geçici bir değişkene kaydedin.
  • for (i=2; i<=NF; i++) $(i-1)=$i N. alan değerini (N-1). alana kaydedin.
  • $NF=ailk değeri ( $1) son alana kaydedin .
  • {}1marka sadık durum awkvarsayılan eylemi gerçekleştirmek: {print $0}.

Bu şekilde, başka bir alan ayırıcınız varsa, sonuç da iyidir:

$ cat c
AE-United-Arab-Emirates
AG-Antigua-&-Barbuda
AN-Netherlands-Antilles
AS-American-Samoa
BA-Bosnia-and-Herzegovina
BF-Burkina-Faso
BN-Brunei-Darussalam

$ awk 'BEGIN{OFS=FS="-"}{a=$1; for (i=2; i<=NF; i++) $(i-1)=$i; $NF=a}1' c
United-Arab-Emirates-AE
Antigua-&-Barbuda-AG
Netherlands-Antilles-AN
American-Samoa-AS
Bosnia-and-Herzegovina-BA
Burkina-Faso-BF
Brunei-Darussalam-BN

1

Özel durumunuz için işe yarıyor gibi görünüyor.

awk '{ f = $1; i = $NF; while (i <= 0); gsub(/^[A-Z][A-Z][ ][ ]/,""); print $i, f; }'

1

seçenek 1

Awk'nin bazı sürümleriyle çalışan bir çözüm var:

awk '{ $(NF+1)=$1;$1="";$0=$0;} NF=NF ' infile.txt

Açıklama:

       $(NF+1)=$1                          # add a new field equal to field 1.
                  $1=""                    # erase the contents of field 1.
                        $0=$0;} NF=NF      # force a re-calc of fields.
                                           # and use NF to promote a print.

Sonuç:

United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

Ancak bu, awk'nin eski sürümlerinde başarısız olabilir.


seçenek 2

awk '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

Yani:

awk '{                                      # call awk.
       $(NF+1)=$1;                          # Add one trailing field.
                  $1="";                    # Erase first field.
                        sub(OFS,"");        # remove leading OFS.
                                    }1'     # print the line.

Silinmesi gereken şeyin FS değil OFS olduğunu unutmayın. $ 1 alanı atandığında satır yeniden hesaplanır. Bu, tüm FS çalıştırmalarını bir OFS'ye değiştirir.


Ancak bu seçenek bile, OFS'nin değiştirilmesiyle açıkça gösterildiği gibi, birkaç sınırlayıcıyla hala başarısız oluyor:

awk -v OFS=';' '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

Bu satırın çıktısı:

United;Arab;Emirates;AE
Antigua;&;Barbuda;AG
Netherlands;Antilles;AN
American;Samoa;AS
Bosnia;and;Herzegovina;BA
Burkina;Faso;BF
Brunei;Darussalam;BN

Bu, FS çalıştırmalarının bir OFS olarak değiştirildiğini ortaya çıkarır.
Bundan kaçınmanın tek yolu, alanın yeniden hesaplanmasını önlemektir.
Yeniden hesaplamayı önleyebilecek bir işlev alttır.
İlk alan yakalanabilir, ardından $ 0'dan sub ile çıkarılabilir ve ardından her ikisi de yeniden yazdırılabilir.

3. Seçenek

awk '{ a=$1;sub("[^"FS"]+["FS"]+",""); print $0, a;}' infile.txt
       a=$1                                   # capture first field.
       sub( "                                 # replace: 
             [^"FS"]+                         # A run of non-FS
                     ["FS"]+                  # followed by a run of FS.
                            " , ""            # for nothing.
                                  )           # Default to $0 (the whole line.
       print $0, a                   # Print in reverse order, with OFS.


United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

FS, OFS'yi değiştirsek ve / veya daha fazla sınırlayıcı eklesek bile işe yarıyor.
Girdi dosyası şu şekilde değiştirilirse:

AE..United....Arab....Emirates
AG..Antigua....&...Barbuda
AN..Netherlands...Antilles
AS..American...Samoa
BA..Bosnia...and...Herzegovina
BF..Burkina...Faso
BN..Brunei...Darussalam

Ve komut şu şekilde değişir:

awk -vFS='.' -vOFS=';' '{a=$1;sub("[^"FS"]+["FS"]+",""); print $0,a;}' infile.txt

Çıktı şu şekilde olacaktır (sınırlayıcılar hala korunmaktadır):

United....Arab....Emirates;AE
Antigua....&...Barbuda;AG
Netherlands...Antilles;AN
American...Samoa;AS
Bosnia...and...Herzegovina;BA
Burkina...Faso;BF
Brunei...Darussalam;BN

Komut birkaç alana genişletilebilir, ancak yalnızca modern awks ve --re-interval seçeneği etkinken. Orijinal dosyadaki şu komut:

awk -vn=2 '{a=$1;b=$2;sub("([^"FS"]+["FS"]+){"n"}","");print $0,a,b;}' infile.txt

Bunu çıkaracak:

Arab Emirates AE United
& Barbuda AG Antigua
Antilles AN Netherlands
Samoa AS American
and Herzegovina BA Bosnia
Faso BF Burkina
Darussalam BN Brunei

1

Başka bir Perl çözümüne açıksanız:

perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file

0

Bir de sed seçeneği var ...

 sed 's/\([^ ]*\)  \(.*\)/\2 \1/' inputfile.txt

Açıklaması ...

Swap
\([^ ]*\) = Match anything until we reach a space, store in $1
\(.*\)    = Match everything else, store in $2
With
\2        = Retrieve $2
\1        = Retrieve $1

Daha ayrıntılı bir şekilde açıklandı ...

s    = Swap
/    = Beginning of source pattern
\(   = start storing this value
[^ ] = text not matching the space character
*    = 0 or more of the previous pattern
\)   = stop storing this value
\(   = start storing this value
.    = any character
*    = 0 or more of the previous pattern
\)   = stop storing this value
/    = End of source pattern, beginning of replacement
\2   = Retrieve the 2nd stored value
\1   = Retrieve the 1st stored value
/    = end of replacement

0

Yine başka bir yol ...

... bu, 2 ile NF arasındaki alanları FS ile birleştirir ve her giriş satırı için bir satır çıkarır

awk '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'

Bunu, çalışma dizinimde hangi dosyaların değiştirildiğini görmek için git ile kullanıyorum:

git diff| \
    grep '\-\-git'| \
    awk '{print$NF}'| \
    awk -F"/" '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'

-3

Cat komutunu kullanmanın başka ve kolay yolu

cat filename | awk '{print $2,$3,$4,$5,$6,$1}' > newfilename

Olumsuz oy verdim çünkü bu dinamik bir yaklaşım değil. Bununla, argüman sayısını bilmeniz ve verilerinizin tutarlı olduğunu varsaymanız gerekir. Veriler neredeyse hiçbir zaman tutarlı değildir ve yaklaşımınız bunu çoğu zaman hesaba katmalıdır.
xh3b4sd
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.