7

次のファイルがあります。

<tr class="in">
  <th scope="row">In</th>
  <td>1.2 kB/s (0.0%)</td>
  <td>8.3 kB/s (0.0%) </td>
  <td>3.2 kB/s (0.0%) </td>
</tr>
<tr class="out">
  <th scope="row">Out</th>
  <td>6.7 kB/s (0.6%) </td>
  <td>4.2 kB/s (0.1%) </td>
  <td>1.5 kB/s (0.6%) </td>
</tr>

次のように、各秒の間の値を取得<td></td>してファイルに保存したい:

8.3
4.2

これまでの私のコード:

# get the lines with <td> tags
cat tmp.txt | grep '<td>[0-9]*.[0-9]' > tmp2.txt

# delete whitespaces
sed -i 's/[\t ]//g' tmp2.txt

# remove <td> tag
cat tmp2.txt | sed "s/<td>//g" > tmp3.txt

# remove "kB/s (0.0%)"
cat tmp3.txt | sed "s/kB\/s\((.*)\)//g" > tmp4.txt

# remove </td> tag and save to traffic.txt
cat tmp4.txt | sed "s/<\/td>//g" > traffic.txt

#rm -R -f tmp*

これを一般的な方法で行うにはどうすればよいですか?このコードは本当に初心者です..

前もってありがとう、マーリー

4

5 に答える 5

14

オプションを使用し-eます(GNU sedを使用している場合)。マニュアルから:

e [コマンド]このコマンドを使用すると、シェルコマンドからの入力をパターンスペースにパイプできます。パラメーターがない場合、eコマンドはパターン・スペースにあるコマンドを実行し、パターン・スペースを出力に置き換えます。末尾の改行は抑制されます。

代わりに、パラメーターが指定されている場合、eコマンドはそれをコマンドとして解釈し、その出力を出力ストリームに送信します。コマンドは複数の行にまたがって実行できますが、最後を除いてすべてバックスラッシュで終わります。

どちらの場合も、実行するコマンドにNUL文字が含まれている場合、結果は未定義です。

rコマンドとは異なり、コマンドの出力はすぐに出力されることに注意してください。代わりに、rコマンドは出力を現在のサイクルの終わりまで遅らせます。

したがって、あなたの場合、あなたは次のことができます:

cat tmp.txt | grep '<td>[0-9]*.[0-9]' \
| sed -e 's/[\t ]//g' \
-e "s/<td>//g" \
-e "s/kB\/s\((.*)\)//g" \
-e "s/<\/td>//g" > traffic.txt

別の方法で次のように書くこともできます。

grep "<td>.*</td>" tmp.txt | sed 's/<td>\([0-9.]\+\).*/\1/g'

\+1つ以上のインスタンスに一致しますが、GNU以外のバージョンのsedでは機能しません。(たとえば、MacにはBSDがあります)

以下の@tripleeeのコメントの助けを借りて、これは私が入手できる最も洗練されたバージョンであり、GNU以外のバージョンでsedも機能します。

sed -n 's/<td>\([0-9]*.[0-9]*\).*/\1/p' tmp.txt

補足として、各出力を保存する代わりに、各sedを介して出力を単純にパイプすることもできます。これは、アドホックタスクで一般的に行われていることです。

  cat tmp.txt | grep '<td>[0-9]*.[0-9]' \
    | sed -e 's/[\t ]//g' \
    | sed "s/<td>//g" \
    | sed "s/kB\/s\((.*)\)//g" \
    | sed "s/<\/td>//g" > traffic.txt

オプションの-e方が効率的ですが、配管オプションの方が便利だと思います。

于 2012-05-31T10:30:56.487 に答える
3

これはうまくいくかもしれません(GNU sed):

 sed '/^<tr/,/^<\/tr>/!d;/<td/H;/^<\/tr/!d;x;s/\n//g;s/<td>/\n/2;s/.*\n\(\S*\).*/\1/' file

説明:

  • 開始タグ<tr>と終了</tr>タグの間の行に注目してください。/^<tr/,/^<\/tr>/!d
  • <td>ラインを保留スペース (HS) に格納します。/<td/H
  • 範囲内の最後の行を除くすべての行を削除します。/^<\/tr/!d
  • HSに交換。x
  • すべての改行を削除します。s/\n//g
  • 2nd<td>を改行に置き換えます。s/<td>/\n/2
  • 挿入された改行に続く最初のスペース以外のフィールドを除いて、HS 内のすべてのテキストを削除し、印刷します。s/.*\n\(\S*\).*/\1/
于 2012-05-31T12:02:24.170 に答える
2

中かっこを使用して、アドレスまたはアドレスのセットによって操作されるブロックを作成できます。

sed -n '/<td>[0-9]*.[0-9]/ {s/[\t ]//g; s/<td>//g; s/kB\/s\((.*)\)<\/td>//g;p}' tmp.txt

2 行目と 4 行目を取得するために、おそらく sed のホールド スペースとパターン スペースを使用してトリッキーなことを行うことができると思います (この方法でファイルのダブル スペースを取り消すことができるソリューションを見てきました)。

于 2012-05-31T12:32:50.647 に答える
1

複数の sed の実行に関する質問には回答があったようですが、sed はこれには不適切なツールです。入力形式が厳密で、<tr>常に行の先頭にあり、探している td タグの前に常に正確に 2 つのスペースがあると仮定すると (そうでない場合、この解決策は簡単に変更できます)、できる:

awk -F'</?td>' '/^<tr/{i=0} /^  <td/{i++} i==2{print $2}' input-file

最初の引数は awk に各行を<td>または</td>で分割するように指示するため、関心のあるデータは 2 番目のフィールドになります。2 番目の引数の最初の節は、行頭に<tr現れるたびにカウンター i をゼロにリセットします。次の増分は、2i<tdのスペースの後に表示されます。最後は、2 行目の 2 番目のフィールドを出力し<td>ます。最後の引数は入力ファイルを指定します。

もちろん、それは<td>タグ間のすべてを提供しますが、これはあなたが望むものではありません。<td>と最初の空白の間のテキストのチャンクを取得するには、次を試してください。

awk '/^<tr/{i=0} /^  <td/{i++} i==2{gsub( "<td>", ""); print $1}' input-file
于 2012-05-31T12:47:52.233 に答える