拥有以下文件:
<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*
我怎样才能这样做呢?这段代码真的很无比..
先谢谢, 马利
答案 0 :(得分:11)
使用-e
选项。在man sed
所以在你的情况下你可以这样做:
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'
\+
匹配一个或多个实例,但它不适用于非GNU版本的sed。 (例如,Mac有BSD)
在下面的@ tripleee评论的帮助下,这是我能得到的最精致的版本,它也适用于非sed
的GNU版本:
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
选项效率更高,但我认为管道选项更方便。
答案 1 :(得分: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>
行。 /<td/H
/^<\/tr/!d
x
s/\n//g
<td>
。 s/<td>/\n/2
s/.*\n\(\S*\).*/\1/
答案 2 :(得分:2)
您可以使用大括号创建一个由一个地址或一组地址操作的块:
sed -n '/<td>[0-9]*.[0-9]/ {s/[\t ]//g; s/<td>//g; s/kB\/s\((.*)\)<\/td>//g;p}' tmp.txt
我认为你可以用sed的hold和pattern空间来做一些棘手的事情,以获得第二行和第四行,(我已经看到了可以通过这种方式撤消文件的双倍间距的解决方案。)
答案 3 :(得分:1)
[编辑]感谢巴顿指出错误。更正版本:
cat tmp.txt | grep td | sed 's/<td>\([0-9]\.[0-9]\).*/\1/g' > newtmp.txt
sed -n '2,${p;n;n}' newtmp.txt > final.txt; rm newtmp.txt
第一行将在每行上的td后选出digit.digit模式。
第二行从第二行开始打印每三行(这有效地为您提供文件中每组三个中的第二行)。
答案 4 :(得分:1)
关于运行多个sed的问题似乎已得到解答,但是sed是错误的工具。假设输入格式是刚性的,并且<tr>
始终位于一行的开头,并且您要查找的td标记总是在该行前面恰好有2个空格(如果不是这样,则可以轻松修改此解决方案如果是这样的话,你可以这样做:
awk -F'</?td>' '/^<tr/{i=0} /^ <td/{i++} i==2{print $2}' input-file
第一个参数告诉awk拆分<td>
或</td>
上的每一行,因此您感兴趣的数据将成为第二个字段。只要<tr
出现在一行的开头,第二个参数的第一个子句就会将计数器i重置为零。每次i
在2个空格后出现,下一个增量<td
。最后一个打印第二个<td>
行的第二个字段。最后一个参数指定了您的输入文件。
当然,这会为您提供<td>
标签之间的所有内容,我认为这不是您想要的。要在<td>
和第一个空格之间获取文本块,请尝试:
awk '/^<tr/{i=0} /^ <td/{i++} i==2{gsub( "<td>", ""); print $1}' input-file