Como descartar vários espaços para um usando sed?

57

sed no AIX não está fazendo o que eu acho que deveria. Estou tentando substituir vários espaços com um único espaço na saída do IOSTAT:

# 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 deve pesquisar & substitua (s) espaços múltiplos (/ [] * /) por um único espaço (/ /) para o grupo inteiro (/ g) ... mas não é só isso ... o espaçamento de cada caractere.

O que estou fazendo de errado? Eu sei que tem que ser algo simples ... AIX 5300-06

edit: Eu tenho outro computador com mais de 10 discos rígidos. Estou usando isso como um parâmetro para outro programa para fins de monitoramento.

O problema que eu encontrei foi que "awk '{print $ 5}' não funcionou porque eu estou usando $ 1, etc no estágio secundário e deu erros com o comando Print. Eu estava procurando por um grep / sed / versão de corte.O que parece funcionar é:

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

Os [] s eram "0 ou mais" quando eu pensei que eles significavam "apenas um". Removendo os suportes, funcionou. Três respostas muito boas dificultam rapidamente a escolha da "resposta".

    
por WernerCD 19.08.2011 / 16:45

6 respostas

49

O uso de grep é redundante, sed pode fazer o mesmo. O problema está no uso de * que corresponde a 0 espaços, você tem que usar \+ :

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

Se o seu sed não suportar \+ metachar, faça

iostat | sed -n '/hdisk1/s/  */ /gp'
    
por 19.08.2011 / 17:06
60

/[ ]*/ corresponde a zero ou mais espaços, de modo que a string vazia entre os caracteres coincide.

Se você estiver tentando corresponder "um ou mais espaços", use um destes:

... | sed 's/  */ /g'
... | sed 's/ \{1,\}/ /g'
... | tr -s ' '
    
por 19.08.2011 / 17:06
9

Altere seu operador * para + . Você está combinando zero ou mais do caractere anterior, que corresponde a todos os caracteres porque tudo o que não é um espaço é ... um ... zero instâncias de espaço. Você precisa combinar um ou mais. Na verdade, seria melhor combinar dois ou mais

A classe de caractere entre colchetes também não é necessária para corresponder a um caractere. Você pode simplesmente usar:

s/  \+/ /g

... a menos que você queira corresponder tabulações ou outros tipos de espaços, a classe de caracteres é uma boa ideia.

    
por 19.08.2011 / 17:14
7

Você sempre pode corresponder a última ocorrência em uma sequência de algo como:

s/\(sequence\)*//

E então você está no caminho certo, mas em vez de substituir a sequência por um espaço - substitua-a por sua última ocorrência - um único espaço. Desse modo, se uma sequência de espaços for correspondida, a sequência será reduzida a um único espaço, mas se a sequência nula for correspondida, a sequência nula será substituída por ela mesma - e nenhum dano, nenhuma falta. Então, por exemplo:

sed 's/\( \)*//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

OUTPUT

# 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

Tudo o que foi dito, é provavelmente muito melhor evitar regexps completamente nessa situação e, em vez disso:

tr -s \  <infile
    
por 24.11.2014 / 00:56
5

Observe que você também pode fazer o que tentar, ou seja,

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

por

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

que pode ser especialmente útil se você tentar acessar outros campos também e / ou calcular algo assim:

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

Você pode usar o seguinte script para converter vários espaços em um único espaço, uma TAB ou qualquer outra string:

$ 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"
    
por 28.10.2016 / 21:00