Bash 替换现有文件中浮点数的精度
我有大量以下格式的大文件Bash 替换现有文件中浮点数的精度,bash,Bash,我有大量以下格式的大文件 step 80 1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4
step 80
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
step 90
1.54045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
1.16545e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07
...
数字都是不同的(因为我的懒惰,这里有些数字是相同的)
我想更改浮点数的精度。也就是说,我想将上一个文件替换为:
step 80
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
step 90
1.54e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.16e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
...
如果所需精度为小数点后2位
如何以一种高效的方式和低内存使用率(也就是说,我不必将整个文件加载到内存中)来实现这一点
最好是使用bash脚本的解决方案。如果数字的“长”部分是在
'e'
前面一次超过2位的唯一序列,则作为快速而肮脏的解决方案
sed -i "s/\([0-9]\{2\}\)[0-9]*e/\1e/g" <filename>
sed-i“s/\([0-9]\{2\}\)[0-9]*e/\1e/g”
——搜索“s
--开始“搜索”术语/
--开始分组\(
--数字[0-9]
--…其中两个(针对不同的输出精度进行编辑)\{2\}
--端组\)
——后跟任意数字[0-9]*
——后跟e
'e'
--结束“搜索”术语,开始“替换”术语/
--第一组的内容(前两位数字)\1
--和e
'e'
--结束“替换”术语/
——每行执行任意次数(“全局”)g
-i
选项(GNU扩展名)在文件中进行替换,因此最好先在不使用-i
的情况下进行尝试,以确保输出符合要求。$sed's/\(\…\)…e/\1e/g'$ sed 's/\(\...\)...e/\1e/g' < so.txt
step 80
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
step 90
1.54e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.16e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07
步骤80
1.10e+071.10e+071.20e+072.40e+074.30e+07
1.10e+071.10e+071.20e+072.40e+074.30e+07
1.10e+071.10e+071.20e+072.40e+074.30e+07
1.10e+071.10e+071.20e+072.40e+074.30e+07
步骤90
1.54e+071.10e+071.20e+072.40e+074.30e+07
1.16e+071.10e+071.20e+072.40e+074.30e+07
1.10e+071.10e+071.20e+072.40e+074.30e+07
1.10e+071.10e+071.20e+072.40e+074.30e+07
您可以使用Perl逐行读取文件,并使用以下命令重新格式化数字: 使用awk,您可以执行以下操作:
awk 'NF==5{printf "%.2e\t%.2e\t%.2e\t%.2e\t%.2e\n", $1, $2, $3, $4, $5; next}1' file
如果列数未知,请使用循环:
awk '!/^step/{for(i=1;i<=NF;i++) printf "%.2e%s", $i,i==NF?"\n":"\t";next}1' file
awk'!/^step/{for(i=1;它的格式是这样的,因为其中有选项卡。;-)@DevSolar你是对的!@LutzHorn:非常感谢。你的条件不成立。步骤可以是任何正整数,大的有许多数字,或小的。@becko应该很容易改进这个答案的匹配。你现在有了一些好的解决方案,使用它们。@becko:添加了'e'
。应该这样做。…
?这很好是的,在e
前面匹配任何字符都是非常特别的。:-d这不好用…有些条目最终会有更多的数字,0.000
会被精确的0
取代,这是不正确的可取的。我不能指出这个问题,我将尝试提出一个简单的例子。这太糟糕了,因为sed
非常快。我不知道有多少列。而且可能不止5列,所以逐个列出它们不是一个选项。你能改进一下吗?对于我尝试的大文件,循环非常慢。这Works非常完美。唯一的缺点是sed
速度更快…但它现在工作得并不完美。我怎么能在gnu内部称之为并行。这不起作用parallel--jobs 20 perl-ape'!/^step/&s/(\s+)/sprintf(%.1e',$1)/ge'{}>{}.fixed:::*
@becko也许可以问一个新问题来解决这个问题。另外,可以省略切换到perl
的-a
(根据编辑)。
awk '!/^step/{for(i=1;i<=NF;i++) printf "%.2e%s", $i,i==NF?"\n":"\t";next}1' file