it-swarm.com.de

Wie kann man mit sed mehrere Leerzeichen zu einem entfernen?

sed unter AIX macht nicht das, was ich denke, dass es sollte. Ich versuche, mehrere Leerzeichen in der Ausgabe von IOSTAT durch ein einzelnes Leerzeichen zu ersetzen:

# 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 sollte mehrere Leerzeichen (/ [] * /) durch ein einzelnes Leerzeichen (/ /) für die gesamte Gruppe (/ g) suchen und ersetzen ... aber es tut nicht nur das ... seinen Abstand zu jedem Zeichen.

Was mache ich falsch? Ich weiß, es muss etwas Einfaches sein ... AIX 5300-06

edit : Ich habe einen anderen Computer mit mehr als 10 Festplatten. Ich verwende dies als Parameter für ein anderes Programm zu Überwachungszwecken.

Das Problem, auf das ich gestoßen bin, war, dass "awk '{print $ 5}' nicht funktioniert hat, weil ich in der Sekundärstufe $ 1 usw. verwende und Fehler mit dem Befehl Drucken gemacht habe. Ich habe nach einer grep/sed/cut-Version gesucht Was zu funktionieren scheint, ist:

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

Die [] s waren "0 oder mehr", als ich dachte, sie bedeuteten "nur eine". Durch Entfernen der Klammern funktionierte es. Drei sehr gute Antworten machen es sehr schnell schwierig, die "Antwort" zu wählen.

72
WernerCD

Die Verwendung von grep ist redundant, sed kann dasselbe tun. Das Problem liegt in der Verwendung von *, Die auch 0 Leerzeichen entsprechen. Sie müssen stattdessen \+ Verwenden:

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

Wenn Ihr sed die Metachar \+ Nicht unterstützt, tun Sie dies

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

/[ ]*/ entspricht null oder mehr Leerzeichen, sodass die leere Zeichenfolge zwischen den Zeichen übereinstimmt.

Wenn Sie versuchen, "ein oder mehrere Leerzeichen" zuzuordnen, verwenden Sie eines der folgenden Elemente:

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

Ändere dein * Operator zu einem +. Sie stimmen mit null oder mehr des vorherigen Zeichens überein, das mit jedem Zeichen übereinstimmt, da alles, was kein Leerzeichen ist, ... ähm ... null Leerzeicheninstanzen sind. Sie müssen mit EINEM oder mehreren übereinstimmen. Eigentlich wäre es besser, zwei oder mehr zusammenzubringen

Die in Klammern gesetzte Zeichenklasse ist auch nicht erforderlich, um ein Zeichen abzugleichen. Sie können einfach verwenden:

s/  \+/ /g

... wenn Sie nicht auch Tabulatoren oder andere Arten von Leerzeichen zuordnen möchten, ist die Zeichenklasse eine gute Idee.

15
Caleb

Sie können immer das letzte Vorkommen in einer Folge von Folgendem abgleichen:

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

Sie sind also auf dem richtigen Weg, aber anstatt die Sequenz durch ein Leerzeichen zu ersetzen - ersetzen Sie sie durch das letzte Vorkommen - ein einzelnes Leerzeichen. Auf diese Weise wird, wenn eine Folge von Leerzeichen is übereinstimmt, die Folge auf ein einzelnes Leerzeichen reduziert. Wenn jedoch die Nullzeichenfolge übereinstimmt, wird die Nullzeichenfolge durch sich selbst ersetzt - und kein Schaden, kein Foul. Also zum Beispiel:

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

AUSGABE

# 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

Trotzdem ist es wahrscheinlich weitaus besser, Regexps in dieser Situation vollständig zu vermeiden und stattdessen Folgendes zu tun:

tr -s \  <infile
8
mikeserv

Beachten Sie, dass Sie auch das tun können, was Sie versuchen

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

durch

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

dies kann besonders nützlich sein, wenn Sie später versuchen, auch auf andere Felder zuzugreifen und/oder etwas zu berechnen - wie folgt:

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

Mit dem folgenden Skript können Sie mehrere Leerzeichen in ein einzelnes Leerzeichen, eine TAB oder eine andere Zeichenfolge konvertieren:

$ 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