it-swarm-eu.dev

Jak odstranit několik mezer do jednoho pomocí sed?

sed na AIX nedělá to, co si myslím, že by mělo. Ve výstupu IOSTAT se snažím nahradit více mezer jedním prostorem:

# 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 by měl hledat a nahradit více mezer (/ [] * /) jedním mezerou (/ /) pro celou skupinu (/ g) ... ale nedělá to jen to ... tím, že rozdělí jednotlivé znaky.

Co dělám špatně? Vím, že to musí být něco jednoduchého ... AIX 5300-06

edit: Mám další počítač, který má 10+ pevných disků. Používám to jako parametr pro jiný program pro účely monitorování.

Problém, na který jsem narazil, bylo to, že „awk“ {print $ 5} 'nefungovalo, protože používám $ 1 atd. V sekundární fázi a dával jsem chyby příkazem Print. Hledal jsem verzi grep/sed/cut Zdá se, že funguje:

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

[] Byly "0 nebo více", když jsem si myslel, že znamenají "jen jeden". Odstranění držáků to fungovalo. Tři velmi dobré odpovědi opravdu rychle ztěžují výběr „odpovědi“.

72
WernerCD

Použití grep je nadbytečné, sed může udělat totéž. Problém je v použití *, které odpovídají také 0 mezerám, musíte použít \+ namísto:

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

Pokud váš sed nepodporuje \+ metachar, pak ano

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

/[ ]*/ odpovídá nula nebo více mezer, takže prázdný řetězec mezi znaky odpovídá.

Pokud se snažíte shodovat „jeden nebo více mezer“, použijte jeden z těchto:

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

Změn svůj * operátor k +. Odpovídá nule nebo více předchozímu znaku, který odpovídá každé postavě, protože vše, co není mezerou, je ... um ... nula instancí prostoru. Musíte odpovídat jeden nebo více. Ve skutečnosti by bylo lepší srovnávat dva nebo více

Třída s hranatými znaky není také nutná pro přiřazení jednoho znaku. Stačí použít:

s/  \+/ /g

... pokud nechcete, aby odpovídaly karty nebo jiné druhy mezer, pak je třída znaků dobrý nápad.

15
Caleb

Vždy se můžete shodovat s posledním výskytem v sekvenci:

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

A tak jste na správné cestě, ale raději než nahrazení sekvence mezerou - nahrazením posledním výskytem - jediným mezerou. Pokud tedy dojde ke shodě posloupnosti mezer is, pak se posloupnost zmenší na jediný prostor, ale pokud se porovná nulový řetězec, nahradí se nulový řetězec sám sebou - a žádné poškození, žádná chyba. Například:

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

VÝSTUP

# 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

Vše, co bylo řečeno, je pravděpodobně mnohem lepší se v této situaci úplně vyhnout regexpsům a místo toho udělat:

tr -s \  <infile
8
mikeserv

Všimněte si, že můžete také dělat to, o co se pokoušíte

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

podle

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

což může být zvláště užitečné, pokud se později pokusíte také získat přístup k jiným polím a/nebo něco spočítat - například toto:

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

Následující skript můžete použít k převodu více mezer na jeden prostor, tabulku TAB nebo jakýkoli jiný řetězec:

$ 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"
0
Brad Parks