it-swarm.it

Come spogliare più spazi su uno usando sed?

sed su AIX non sta facendo quello che penso dovrebbe. Sto cercando di sostituire più spazi con un singolo spazio nell'output di 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 dovrebbe cercare e sostituire (s) più spazi (/ [] * /) con un singolo spazio (/ /) per l'intero gruppo (/ g) ... ma non lo sta solo facendo ... spaziando ogni personaggio.

Che cosa sto facendo di sbagliato? So che deve essere qualcosa di semplice ... AIX 5300-06

modifica: Ho un altro computer con più di 10 dischi rigidi. Sto usando questo come parametro per un altro programma a scopo di monitoraggio.

Il problema che ho riscontrato è che "awk '{print $ 5}' non ha funzionato perché sto usando $ 1, ecc. Nella fase secondaria e ha dato errori con il comando Print. Stavo cercando una versione grep/sed/cut Ciò che sembra funzionare è:

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

Gli [] erano "0 o più" quando pensavo che significassero "solo uno". La rimozione delle parentesi ha funzionato. Tre risposte molto valide rendono molto rapidamente difficile scegliere la "risposta".

72
WernerCD

L'uso di grep è ridondante, sed può fare lo stesso. Il problema è nell'uso di * che corrispondono anche a 0 spazi, devi usare \+ anziché:

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

Se sed non supporta \+ metachar, quindi esegui

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

/[ ]*/ corrisponde a zero o più spazi, quindi la stringa vuota tra i caratteri corrisponde.

Se stai cercando di abbinare "uno o più spazi", usa uno di questi:

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

Cambia il tuo * operatore a un +. Stai abbinando zero o più del carattere precedente, che corrisponde a ogni personaggio perché tutto ciò che non è uno spazio è ... um ... zero istanze di spazio. Devi abbinare UNO o più. In realtà sarebbe meglio abbinarne due o più

Anche la classe di caratteri tra parentesi non è necessaria per abbinare un carattere. Puoi semplicemente usare:

s/  \+/ /g

... a meno che tu non voglia abbinare schede o altri tipi di spazi, allora la classe di caratteri è una buona idea.

15
Caleb

Puoi sempre abbinare l'ultima occorrenza in una sequenza di qualcosa come:

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

E così sei sulla strada giusta, ma invece di sostituire la sequenza con uno spazio - sostituiscilo con la sua ultima occorrenza - un singolo spazio. In questo modo se una sequenza di spazi è corrisponde, allora la sequenza viene ridotta a un singolo spazio, ma se la stringa nulla viene abbinata, la stringa nulla viene sostituita con se stessa e nessun danno, nessun fallo. Quindi, per esempio:

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

PRODUZIONE

# 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

Detto questo, è probabilmente molto meglio evitare completamente le regexps in questa situazione e invece:

tr -s \  <infile
8
mikeserv

Nota che puoi anche fare ciò che cerchi, cioè

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

di

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

che potrebbe essere particolarmente utile se in seguito si tenta di accedere anche ad altri campi e/o calcolare qualcosa, come questo:

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

È possibile utilizzare il seguente script per convertire più spazi in un singolo spazio, una TAB o qualsiasi altra stringa:

$ 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