Sed kullanarak bire çok boşluk bırakma nasıl yapılır?


69

sedAIX üzerinde olması gerektiğini düşündüğüm şeyi yapmıyor. Birden çok alanı IOSTAT çıktısında tek bir boşlukla değiştirmeye çalışıyorum:

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

#iostat|grep "hdisk1"|sed -e"s/[ ]*/ /g"
 h d i s k 1 0 . 1 6 . 3 0 . 5 6 3 3 4 5 8 8 0 1 1 2 4 3 2 3 5 4

sed, tüm grup (/ g) için tek bir boşlukla (/ /) birden fazla boşluk (/ [] * /) aramalı ve değiştirmelidir ... ancak sadece bunu yapmakla kalmaz ...

Neyi yanlış yapıyorum? Biliyorum basit bir şey olmalı ... AIX 5300-06

düzenleme: 10 + sabit diskleri olan başka bir bilgisayar var. Bunu izleme amacıyla başka bir programa parametre olarak kullanıyorum.

Karşılaştığım sorun, "awk '{print $ 5}' 'in işe yaramamasıydı, çünkü ikincil aşamada $ 1 kullandım ve Print komutuyla hatalar verdim. Grep / sed / cut sürümü arıyordum. İş gibi görünen şey:

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

"Sadece bir" demek istediklerini düşündüğümde [] s "0 veya daha fazla" idi. Parantezleri sökmek çalışmasını sağladı. Üç çok iyi cevap gerçekten hızlı bir şekilde "cevabı" seçmeyi zorlaştırıyor.

Yanıtlar:


52

Kullanımı grepgereksizdir, sedaynısını yapabilirsiniz. Sorun *o eşleşmenin kullanımında da 0 boşluk, \+bunun yerine kullanmak zorundasınız :

iostat | sed -n '/hdisk1/s/ \+/ /gp'

Sizin metachar'ı seddesteklemiyorsa \+, o zaman

iostat | sed -n '/hdisk1/s/  */ /gp'

AIX + destekliyor gibi görünmüyor, ancak [] 'nin kaldırılması hile yapmış gibi görünüyor.
WernerCD

Sed -n sürümünü kullanmayı denedim ... ne oldu, 10 + sürücüye sahip başka bir bilgisayarım var, bu yüzden 1, 10, 11, vb. Yapmaya başlıyor ... Bir boşluk / hdisk1 / eklemeye çalıştım "tanınmayan bir işlev". iş gibi görünüyor >> iostat | grep "hdisk1" | sed -e's / * / / g '
WernerCD

67

/[ ]*/sıfır veya daha fazla boşlukla eşleşir , böylece karakterler arasındaki boş dize eşleşir.

"Bir veya daha fazla boşluk" ile eşleşmeye çalışıyorsanız, bunlardan birini kullanın:

... | sed 's/  */ /g'
... | sed 's/ \{1,\}/ /g'
... | tr -s ' '

Ahh ... [] onu "isteğe bağlı" yapıyor. Bu onu açıklar.
WernerCD

5
@WernerCD, hayır *"isteğe bağlı" yapar. [ ]sadece içinde sadece bir karakter bulunan bir karakter listesi yapar (boşluk). *"Önceki şeyin sıfır veya daha fazlası" anlamına gelen niceleyicidir
glenn jackman

Ahh ... yani daha doğru olmak için, onu tek bir boşluktan / * /, çift boşluktan değiştirmek, o zaman ne yaptıysa. Ben Gottcha.
WernerCD

Sadece çift boşlukları araştıran bir model aramaya çalışıyordum ve çok işe yaradı
minhas23

6
En basit tr -s ' 'çözüm için +1
Andrejs

12

*Operatörünüzü a olarak değiştirin +. Her karakterle eşleşen önceki veya sıfır karakteriyle eşleşiyorsunuz, çünkü boşluk olmayan her şey ... um ... sıfır alan örnekleridir. BİR veya daha fazla eşleştirmeniz gerekir. Aslında iki veya daha fazla maç daha iyi olur

Parantez içindeki karakter sınıfı aynı zamanda bir karakteri eşleştirmek için gerekli değildir. Sadece kullanabilirsiniz:

s/  \+/ /g

... sekmeleri veya diğer tür boşlukları da eşleştirmek istemiyorsanız, karakter sınıfı iyi bir fikirdir.


AIX + desteklemiyor gibi görünüyor.
WernerCD

1
@WernerCD: O zaman deneyin s/ */ /g(bu üç boşluklu, yorum biçimlendirmesi onları daraltıyor ). Yıldız operatörü önceki karakteri isteğe bağlı yapar, bu nedenle iki ya da daha fazla eşleşirseniz, ilk ikisini kendinizle eşleştirmeniz gerekir (iki boşluk), ardından üçüncü ve sonraki boşlukları isteğe bağlı yapmak için üçüncü bir boşluk ve bir yıldız eklemeniz gerekir.
Caleb,

3
@ userunknown: Aslında iki şeyi karıştırmıyorum, diğer herkes :) :) Tek bir alanı tek bir boşlukla değiştirmek anlamsız, bu işlemi sadece en az iki sıralı boşluğu olan maçlarda yapmanız gerekiyor. İki boşluk ve bir artı veya üç boşluk ve bir yıldız, tam olarak ihtiyaç duyulan şeydir.
Caleb

@ userunknown: Çok büyük bir iş değil, sadece biraz işlem süresi kaybı ve maç sayacı gibi şeyleri atıyor.
Caleb,

8

Son olayları istediğiniz gibi dizilişiyle her zaman eşleştirebilirsiniz:

s/\(sequence\)*/\1/

Ve böylece doğru yoldasınız, ancak diziyi bir boşlukla değiştirmek yerine - onu en son oluşumuyla - tek bir boşlukla değiştirin. Boşlukların bir sekans ise bu şekilde bir ve hiçbir zarar, bir kötü - dizisi tek bir boşluk azaltılır, ancak boş şeridi, daha sonra eşleşirse boş dizge kendisi ile değiştirilir eşleşti. Yani, örneğin:

sed 's/\( \)*/\1/g' <<\IN                                    
# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

IN

ÇIKTI

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty: tin tout avg-cpu: % user % sys % idle % iowait
 0.2 31.8 9.7 4.9 82.9 2.5

Disks: % tm_act Kbps tps Kb_read Kb_wrtn
hdisk9 0.2 54.2 1.1 1073456960 436765896
hdisk7 0.2 54.1 1.1 1070600212 435678280
hdisk8 0.0 0.0 0.0 0 0
hdisk6 0.0 0.0 0.0 0 0
hdisk1 0.1 6.3 0.5 63344916 112429672
hdisk0 0.1 5.0 0.2 40967838 98574444
cd0 0.0 0.0 0.0 0 0
hdiskpower1 0.2 108.3 2.3 2144057172 872444176

# iostat | grep hdisk1
hdisk1 0.1 6.3 0.5 63345700 112431123

Bütün bunlar, bu durumda düzenli olarak tamamen regexps önlemek ve bunun yerine muhtemelen daha iyidir:

tr -s \  <infile

4
Gerçek cevabın basitliği için +1,iostat | tr -s \
Wildcard

'tr -s \', 'tr -s ""' ile aynıdır. Boşluğun "\" ile kaçarak dizgede argüman olarak geçirilebileceğini fark etmemi sağladı. Kabuk betiklerinde de kullanılabileceğini görüyorum. Soğuk uygulama
randominstanceOfLivingThing 9:18

5

Yapmaya çalıştığınız şeyi de yapabileceğinizi, yani

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

tarafından

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$re"; done

bu, özellikle daha sonra diğer alanlara da erişmeye ve / veya bir şeyler hesaplamaya kalkarsanız yararlı olabilir - şunun gibi:

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$(( re/1024 )) Mb"; done

Çok hoş. İlk versiyon çalışır. AIX kutularım ikinciye benzemiyor. Üç kutu da çıktı: "$ [re / 1024] Mb". Kullandığım izleme aracı raporlar için dönüşüm içeriyor, bu yüzden benim için "gerekli" bir şey değil, ama hoşuma gitti.
WernerCD

@enzotib Düzeltdiğiniz için teşekkür ederiz while.
rozcietrzewiacz 19:11

@WernerCD Ah, bu $[ .. ]muhtemelen bash'ın son sürümlerinde mevcuttur (belki zsh de). Bunun $(( .. ))yerine cevabı daha taşınabilir bir hale getirdim .
rozcietrzewiacz 19:11

Hile yaptı. Buna bakmak zorunda kalacağım. Şık.
WernerCD

0

Birden çok alanı tek bir alana, TAB'a veya başka bir dizeye dönüştürmek için aşağıdaki betiği kullanabilirsiniz:

$ ls | compress_spaces.sh       # converts multiple spaces to one
$ ls | compress_spaces.sh TAB   # converts multiple spaces to a single tab character
$ ls | compress_spaces.sh TEST  # converts multiple spaces to the phrase TEST
$ compress_spaces.sh help       # show the help for this command

compress_spaces.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: {REPLACE_WITH}

  NOTE: If you pass in TAB, then multiple spaces are replaced with a TAB character

  no args -> multiple spaces replaced with a single space
  TAB     -> multiple spaces replaced with a single tab character
  TEST    -> multiple spaces replaced with the phrase "TEST"

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show help if we're not getting data from stdin
if [ -t 0 ]; then
  show_help
fi

REPLACE_WITH=${1:-' '}

if [ "$REPLACE_WITH" == "tab" ]
then
  REPLACE_WITH=$'\t'
fi
if [ "$REPLACE_WITH" == "TAB" ]
then
  REPLACE_WITH=$'\t'
fi

sed "s/ \{1,\}/$REPLACE_WITH/gp"
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.