sedを使用して複数のスペースを1つに取り除く方法は?


69

sedAIX上では、私が思うはずのことをしていません。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は、グループ全体(/ g)で複数のスペース(/ [] * /)を単一のスペース(/ /)で検索および置換する必要があります。

何が間違っていますか?AIX 5300-06がシンプルなものになったことを知っています。

編集: 10台以上のハードドライブを搭載した別のコンピューターがあります。これを監視目的の別のプログラムのパラメーターとして使用しています。

私が遭遇した問題は、「awk '{print $ 5}'がセカンダリステージで$ 1などを使用し、Printコマンドでエラーが発生したために機能しなかったということでした。grep/ sed / cutバージョンを探していました。動作するように見えるものは次のとおりです。

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

[]は、「1つだけ」を意味すると思ったときに「0以上」でした。ブラケットを取り外すと動作しました。3つの非常に良い答えは、すぐに「答え」を選ぶのを難しくします。

回答:


52

の使用grepは冗長でsed、同じことができます。問題は*そのスペースの使用にもスペースがないことにあり、\+代わりに使用する必要があります:

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

あなたsed\+メタチャーをサポートしていない場合は、

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

AIXは+をサポートしていないように見えますが、[]を削除するとうまくいったようです。
WernerCD

私はsed -nバージョンを使用してみました...どうなりますか?10台以上のドライブを搭載した別のコンピューターがあるので、1、10、11などを実行し始めました。スペース/ hdisk1 /を追加しようとしました。 「認識されない機能」。動作しているようです>> iostat | grep "hdisk1" | sed -e's / * / / g '
WernerCD

67

/[ ]*/ゼロ個以上のスペースと一致するため、文字間の空の文字列が一致します。

「1つ以上のスペース」を一致させようとしている場合は、次のいずれかを使用します。

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

ああ... []は「オプション」にします。なるほどね。
WernerCD

5
@ WernerCD、no *は「オプション」にします。[ ]1文字(スペース)のみの文字のリストを作成します。*「前のもののゼロまたはそれ以上」を意味する量指定子
です

ああ...それで、より正確にするために、単一のスペース/ * /から二重のスペースに変更することが、それをやったことです。わかった。
WernerCD

私はダブルスペースのみを検索するパターンを検索しようとしていましたが、それはクールに
動作しました-minhas23

6
最もシンプルなtr -s ' 'ソリューションの+1
Andrejs

12

*演算子をに変更します+。ゼロ以上の前の文字と一致しています。これは、スペースではないものはすべて... um ...ゼロのインスタンスであるため、すべての文字と一致します。1つ以上を一致させる必要があります。実際には2つ以上を一致させる方が良いでしょう

角括弧で囲まれた文字クラスも、1文字と一致させるために不要です。あなただけを使用することができます:

s/  \+/ /g

...タブや他の種類のスペースも一致させたい場合を除き、文字クラスは良い考えです。


AIXは+をサポートしていないようです。
WernerCD

1
@WernerCD:次に試してみてくださいs/ */ /g(3つのスペースがあり、コメントのフォーマットはそれらを折りたたんでいます)。スター演算子は前の文字をオプションにするため、2つ以上を一致させるには、最初の2つ(スペース2つ)を自分で一致させる必要があります。次に3つ目のスペースとスターを追加して、3つ目以降のスペースをオプションにします。
カレブ

3
@userunknown:実際には私は2つのことをまったく混ぜていません、他の人は誰でもです:)単一のスペースを単一のスペースに置き換えることは無意味です、あなたは少なくとも2つの連続したスペースを持つマッチに対してのみこのアクションを行う必要があります。2つの空白と1つまたは3つの空白と星がまさに必要です。
カレブ

@userunknown:大したことではなく、ほんの少しの処理時間の無駄であり、マッチカウンターのようなものを投げ捨てます。
カレブ

8

次のようなシーケンスで最後に出現したものを常に一致させることができます。

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

そして、あなたは正しい軌道に乗っていますが、シーケンスをスペースに置き換えるのではなく、最後に出現する単一のスペースに置き換えます。そのようにすると、スペースのシーケンス一致した場合、シーケンスは単一のスペースに縮小されますが、ヌル文字列が一致した場合、ヌル文字列はそれ自体で置き換えられます。したがって、たとえば:

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

出力

# 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

とはいえ、この状況では正規表現を完全に避けて、代わりに行う方がはるかに良いでしょう。

tr -s \  <infile

4
真の答えをシンプルにするために+1iostat | tr -s \
ワイルドカード

'tr -s \'は 'tr -s ""'と同じです。「\」でエスケープすることにより、スペースを文字列の引数として渡すことができることを認識しました。シェルスクリプトでも使用できることがわかりました。クールなアプリケーション。
randominstanceOfLivingThing

5

あなたがしようとすることもできることに注意してください、それは

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

沿って

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

これは、後で他のフィールドにもアクセスしたり、何かを計算したりする場合に特に便利です。

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

非常に素晴らしい。最初のバージョンは動作します。私のAIXボックスは2番目のものが好きではないようです。3つのボックスすべてが出力します:「$ [re / 1024] Mb」。私が使用している監視ツールにはレポート用の変換があるため、「必要な」ものではありませんが、気に入っています。
WernerCD

@enzotibを修正していただきありがとうございますwhile
-rozcietrzewiacz

@WernerCDああ、これ$[ .. ]はおそらくbashの最近のバージョン(おそらくzsh)で利用可能です。$(( .. ))代わりに、よりポータブルなものへの回答を更新しました。
-rozcietrzewiacz

それはトリックをしました。それを調べなければなりません。おしゃれ。
WernerCD

0

次のスクリプトを使用して、複数のスペースを単一のスペース、TAB、またはその他の文字列に変換できます。

$ 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"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.