Son x oluşumları dışında bir karakteri değiştirme


9

Ben böyle görünüyor IPs ile ilişkili ana bilgisayar adları bir demet olan bir dosya var:

x-cluster-front-1 192.168.1.2
x-cluster-front-2 192.158.1.10
y-cluster-back-1 10.1.11.99
y-cluster-back-2 10.1.157.38
int.test.example.com 59.2.86.3
super.awesome.machine 123.234.15.6

Bunun gibi görünmesini istiyorum:

x-cluster-front-1 192.168.1.2
x-cluster-front-2 192.158.1.10
y-cluster-back-1 10.1.11.99
y-cluster-back-2 10.1.157.38
int-test-example-com 59.2.86.3
super-awesome-machine 123.234.15.6

Nasıl değiştirebilirim. (nokta) ikinci sütuna göre sıralamayı kolaylaştırmak için - (tire) ile ilk sütundan? İlk boşluğa kadar noktaları değiştirmek için sed kullanmayı ya da her üç noktayı değil son üçünü değiştirmeyi düşünüyordum, ancak normal ifadeyi ve sed'i anlamakta zorlanıyorum. Basit yedekler yapabilirim ama bu kafamın üzerinde!

Bu bash yazdığım daha büyük bir komut dosyasının bir parçasıdır. Bu kısımda sıkışıp kaldım.

Yanıtlar:


7

AWK kullanabilirsiniz

awk '{gsub(/-/,".",$1);print}' infile

açıklama

awkvarsayılan olarak boşlukta bir çizgi ayırır. Böylece, (çizginin ilk sütun $1içinde awk-ese) üzerinde değiştirmelerin gerçekleştirmek istediğiniz biri olacak. Bu amaçla şunları kullanabilirsiniz:

 gsub(regex,replacement,string)

gerekli ikameyi yapmak.

Not gsubiçin desteklenir gawkve nawkancak birçok modern dağıtımlar üzerinde awksoftlink olduğunu gawk.


1
+1 Beni döv. Bence bir açıklama gerçekten de askerlere ve gelecekteki okuyuculara fayda sağlayacak.
Joseph R.

1
@JosephR. Üzgünüm açıklamada iyi değilim ama denedim ve güncelledim ..
Rahul Patil

2
POSIX spesifikasyonu awkdayanmaktadır nawk, bu nedenle tüm modern awkuygulamalara sahip olmalıdır gsub. Solaris'te /usr/xpg4/bin/awkveya ihtiyacınız olabilir nawk.
Stéphane Chazelas

@RahulPatil Sakıncası yoksa, başkalarına yardımcı olacağını düşündüğüm birkaç satır ekledim.
Joseph R.

@JosephR teşekkürler .., şimdi mükemmel görünüyor .. :)
Rahul Patil

6

İlk alanda ikameler yapmanız gerekiyorsa, en iyisi Rahul'ın awk çözümünü kullanmaktır, ancak aralıkları etkileyebileceğine dikkat edin (alanlar aralarında tek bir boşlukla yeniden yazılır).

Bunun yerine yazarak bunu önleyebilirsiniz:

perl -pe 's|\S+|$&=~tr/./-/r|e' file

-pBayrağının "hattı ile girdi dosyası satır okumak ve verdiği komut uygulandıktan sonra her satırı yazdırmak -e". Daha sonra, yerine ( s|pattern|replacement|) boşluk olmayan karakterin ilk dizisi ( \S+eşleşen desen (ile) $&tüm ikame sonra) .ile -. İşin püf noktası s|||e, eoperatörün bir ifadeyi yedek olarak değerlendireceği yerde kullanmaktır . Böylece, bir öncekinin ( tr/./-/) eşleşmesine ( $&) bir tane ( s|||e) uygulayabilirsiniz .

Her yerine gerekirse .bir ile -GNU, son 3 son olanlar hariç sedve varsayarak bir var revkomutu:

rev file | sed 's/\./-/4g' | rev

1
Perl çözümünün ( /rçalışma için) 5.14 veya daha yüksek bir sürüm aldığını unutmayın .
Joseph R.

3

Sed, iş için en kolay araç değil - daha iyi araçlar için diğer cevaplara bakın - ancak yapılabilir.

Değiştirmek için .tarafından -sadece yukarı ilk uzay, kullanımına sbir döngü içinde.

sed -e '
  : a                     # Label "a" for the branching command
  s/^\([^ .]*\)\./\1-/    # If there is a "." before the first space, replace it by "-"
  t a                     # If the s command matched, branch to a
'

(Bazı sed uygulamalarının aynı satırdaki yorumları desteklemediğini unutmayın. GNU sed bunu destekler.)

Bunun yerine, son boşluğa kadar değiştirme işlemini gerçekleştirmek için:

sed -e '
  : a                     # Label "a" for the branching command
  s/\.\(.* \)/-\1/        # If there is a "." before the last space, replace it by "-"
  t a                     # If the s command matched, branch to a
'

Başka bir teknik sed'in tutma alanını kullanır. Değiştirmek istemediğiniz biti bekleme alanına kaydedin, işinizi yapın ve ardından bekleme alanını geri çağırın. Burada, çizgiyi son boşlukta böldüm ve noktaları ilk kısımdaki çizgilerle değiştirdim.

sed -e '
  h           # Save the current line to the hold space
  s/.* / /    # Remove everything up to the last space
  x           # Swap the work space with the hold space
  s/[^ ]*$//  # Remove everything after the last space
  y/./-/      # Replace all "." by "-"
  G           # Append the content of the hold to the work space
  s/\n//      # Remove the newline introduced by G
'

2

Rahul size kullanım durumunuz için kanonik cevap verdiğinden , başlık sorununu yanıtlamak için bir bıçak alacağımı düşündüm: bir regex'in son x olayları hariç hepsini değiştirmek:

perl -pe '
    $count = tr{.}{.}; # Count '.' on the current line
    $x = 3;
    next LINE if $count <= $x;
    while(s{\.}{-}){   # Substitute one '.' with a '-'
        last if ++$i == $count - $x # Quit the loop before the last x substitutions
    }
$i = 0
' your_file

Yukarıdaki kod (test edilmiş), boşlukla ayrılmış alanlara sahip olduğunuzu varsaymaz. Bir satırdaki tüm noktaları, son 3 nokta hariç tire ile değiştirir. 3Kodu istediğiniz gibi değiştirin .


2

Bunun için birçok farklı araç kullanabilirsiniz. Rahul Patil zaten bir gawktane verdi, bu yüzden burada birkaç tane daha var:

  • perl

    perl -lane  '$F[0]=~s/\./-/g; print "@F"' file
    

    -aAnahtar nedenleri boşluk ve diziye Görüntülenen alanlarda tasarruf otomatik olarak bölünmüş giriş hatlarına perl @F. İlk alan, bu nedenle, olacak $F[0]biz (replace böylece s///) tüm oluşumlarını .ile -ilk alana ve daha sonra tüm dizi yazdırın.

  • kabuk

     while read -r a b; do printf "%s %s\n" "${a//./-}" "$b"; done < file 
    

    Burada while döngüsü dosyayı okur ve boşluklara otomatik olarak ayrılır.Bu iki alan oluşturur $firstve $rest. Yapı, ${first//pattern/replacement}tüm oluşumları yerine patternile replacement.


1 iken perlrun(1)söyleyecektir -a"otomatik bölme modu", ben "olarak düşünmek tercih awkmodu": D
Joseph R.

2

Bu büyük bir kötü regex okumak biraz daha kolay olduğuna inanıyorum. Temelde çizgiyi boşlukta iki alana ayırdım ve ilk bölümde sed kullanıyorum.

while read -r host ip; do
    echo "$(sed 's/\./-/g' <<< "$host") $ip"
done < input_file

Kabuğunuza bağlı olarak sed komutu yerine $ {host //./-} kullanabilirsiniz.


0
sed 's/\./-/' <file name>

gKomutun sonunda kullanmadan bunu yapabilirsiniz… Bu, desenin 1. tekrarının yerini alacak

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.