web-dev-qa-db-fra.com

Comment découper plusieurs espaces en un à l'aide de sed?

sed sur AIX ne fait pas ce que je pense qu'il devrait. J'essaie de remplacer plusieurs espaces par un seul espace dans la sortie d'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 doit rechercher et remplacer (s) plusieurs espaces (/ [] * /) par un seul espace (/ /) pour tout le groupe (/ g) ... mais ce n'est pas seulement cela ... son espacement pour chaque caractère.

Qu'est-ce que je fais mal? Je sais que ça doit être quelque chose de simple ... AIX 5300-06

edit: J'ai un autre ordinateur qui a plus de 10 disques durs. J'utilise ceci comme paramètre d'un autre programme à des fins de surveillance.

Le problème que j'ai rencontré était que "awk '{print $ 5}' ne fonctionnait pas parce que j'utilisais $ 1, etc. dans la phase secondaire et donnais des erreurs avec la commande Print. Je cherchais une version grep/sed/cut Ce qui semble fonctionner est:

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

Les [] s étaient "0 ou plus" quand je pensais qu'ils signifiaient "juste un". La suppression des supports l'a fait fonctionner. Trois très bonnes réponses rendent très rapidement difficile le choix de la "réponse".

72
WernerCD

L'utilisation de grep est redondante, sed peut faire de même. Le problème réside dans l'utilisation de * qui correspondent également à 0 espace, vous devez utiliser \+ au lieu:

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

Si votre sed ne prend pas en charge \+ metachar, alors faites

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

/[ ]*/ correspond à zéro ou plusieurs espaces, donc la chaîne vide entre les caractères correspond.

Si vous essayez de faire correspondre "un ou plusieurs espaces", utilisez l'un d'eux:

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

Change ton * opérateur vers un +. Vous correspondez à zéro ou plus du caractère précédent, ce qui correspond à chaque caractère parce que tout ce qui n'est pas un espace est ... euh ... zéro instance d'espace. Vous devez correspondre à UN ou plusieurs. En fait, il serait préférable de faire correspondre deux ou plusieurs

La classe de caractères entre crochets n'est pas non plus nécessaire pour faire correspondre un caractère. Vous pouvez simplement utiliser:

s/  \+/ /g

... à moins que vous ne vouliez également faire correspondre des tabulations ou d'autres types d'espaces, la classe de caractères est une bonne idée.

15
Caleb

Vous pouvez toujours faire correspondre la dernière occurrence dans une séquence de quelque chose comme:

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

Et vous êtes donc sur la bonne voie, mais plutôt que de remplacer la séquence par un espace - remplacez-la par sa dernière occurrence - un seul espace. De cette façon, si une séquence d'espaces est correspond alors la séquence est réduite à un seul espace, mais si la chaîne nulle est mise en correspondance, alors la chaîne nulle est remplacée par elle-même - et aucun mal, aucune faute. Ainsi, par exemple:

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

PRODUCTION

# 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

Cela dit, il vaut probablement mieux éviter complètement les regexps dans cette situation et faire à la place:

tr -s \  <infile
8
mikeserv

Notez que vous pouvez également faire ce que vous essayez, c'est-à-dire

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

par

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

ce qui pourrait être particulièrement utile si vous essayez d'accéder ultérieurement à d'autres champs et/ou de calculer quelque chose - comme ceci:

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

Vous pouvez utiliser le script suivant pour convertir plusieurs espaces en un seul espace, un TAB ou toute autre chaîne:

$ 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