Fortran Coder

标题: 如何在Fortran中实现像shell里的sed命令那样的文件内容替换 [打印本页]

作者: liudy02    时间: 2018-12-14 19:13
标题: 如何在Fortran中实现像shell里的sed命令那样的文件内容替换
简单点的,例如文件中的某行替换成某一个字符串
稍微难一点的,例如文件中的某些字符替换成某一个字符串
再复杂一点的,例如文件中符合条件的某些行进行特定替换操作或者类似于shell中awk那样的表控操作
其实吧,自行编写特定的Fortran子程序,对只有一行的文件都可以做到
但是Fortran似乎一旦只要写文件,就得从头到尾地写,没法实现Shell那样的中间替换
我曾试想过用Call System("")的语句,“”中是shell命令
这个问题是一次只能写一行,太复杂的shell命令实现不了
更大的问题是这样无法实现shell和Fortran的数据传递,这才是更要命的
各位大神,请问有什么办法没有……
作者: vvt    时间: 2018-12-14 22:19
其实Shell也只能从头到尾地写。但是这些解释型脚本,做了一些封装,使得一个复杂的过程被简单的一个语句代替了而已。
Fortran中你也可以这样,全部读入内存里,在内存里处理、替换、然后决定要保存的时候,再全部写入文件。

此外,你可以把多个Shell语句先写入 .sh 文件,然后 call system 让操作系统执行这个 .sh 脚本。

作者: liudy02    时间: 2018-12-14 22:39
vvt 发表于 2018-12-14 22:19
其实Shell也只能从头到尾地写。但是这些解释型脚本,做了一些封装,使得一个复杂的过程被简单的一个语句代 ...

哈,您这么说我感觉恍然大悟啊
可是还是解决不了一个问题啊,把一个文件全部读入内存,这个操作感觉很扯着蛋啊……
怎么弄呢……
定义一个数据成员是待定长度字符串的派生类型,然后建立一个这样的链表?
不管怎样,这都是一个很耗内存的事情啊,文件多大至少就要耗多大内存呢……
另外,您说的用sh文件在Fortran内执行复杂shell命令确实很有启发
不过,这个还是解决不了shell和Fortran互相传递数据不便的问题,这个有好办法么?
我用建立文件的办法实现过,不过这不是什么好办法,文件I/O是很没有效率的一件事情……
如果想同时利用shell脚本处理文字方便和Fortran数据处理强的优势,这样的互传数据又是很重要的
作者: vvt    时间: 2018-12-15 10:33
说真的,Fortran的文本处理能力的确不怎么样。
你用Shell处理大文件也一样的消耗内存的。并没有什么本质区别。

我对文本处理没有太大的需求,所以了解也不多。
大量的数据互传,没有什么好的思路。
作者: liudy02    时间: 2018-12-15 11:10
vvt 发表于 2018-12-15 10:33
说真的,Fortran的文本处理能力的确不怎么样。
你用Shell处理大文件也一样的消耗内存的。并没有什么本质区 ...

一样耗内存啊,我还以为shell的脚本有什么优化方法能减少内存消耗呢
既然如此,用Fortran给自己写一些类似于sed,awk,head,tail之类的封装至成熟也是可行啊
不过这个有点耗时间,对于一些小问题可能还是想用shell和Fortran混合编程了

至于对于数据互传,看来我的表述方式有问题,让大佬你误解了
我倒不是说能有什么大量数据的互传
就是说有没有什么办法在用Shell和Fortran混合编写的时候,
在内存里两种程序语言间互传数据,目前我是先把数据写到文件里再用另外一种语言去读
这样的文件I/O据说速度很低,应该尽量避免啊,希望能有类似于shell里的管道的方式

举个例子,比如某个文件里我希望读取最后一行第二个空格后的数据
然后接下来这个数据要用于Fortran计算
从文字处理上,直接用shell里的awk命令显然是最省心的
可是问题是用shell读出来了,Fortran程序里却是没有这个数据的,哪怕作为字符串也没有
那么有没有不用文件I/O的方法把这个数据或者字符串传递给Fortran程序呢
当然,大佬你之前说的很对,这个功能可以自己写一个Fortran子程序在Fortran内部实现
但是如果大量涉及到类似的东西的话,就除非自己写一个函数库了
所以我就像问下,如果采用shell和Fortran混合编程结合优势的话有没有什么好办法实现这种数据互传

另外,我不太了解C,是不是C的库里也有类似于sed,awk,head,tail等这样方便的文字处理函数
如果有的话,是不是用C/Fortran混合编程是不是比较容易解决数据互传的问题……
作者: fcode    时间: 2018-12-15 11:30
管道当然可以呀

QQ截图20181215112933.png (119.73 KB, 下载次数: 354)

QQ截图20181215112933.png

作者: liudy02    时间: 2018-12-15 12:48
fcode 发表于 2018-12-15 11:30
管道当然可以呀

哈,谢谢版主,好有趣的功能,非常有启发性
这确实是把通过shell管道得到数据作为Fortran程序的输入了唉
不过还是和我预想的功能有些不太一样,应该还是我描述的不完整
实际上我的程序可能会有shell何Fortran程序来回互传数据啊
唉,还不如完整说下我的问题吧
我其实是想用Fortran写一个vasp用的脚本
实现的功能是多次调用vasp进行计算,根据每次计算得到的能量调整输入的POSCAR文件
在这里,每次从vasp的结果文件中读入能量和改写POSCAR文件都是用Shell文字处理比较方便的
但是对于根据得到的能量进行优化计算,这些都是用Fortran更合适
所以需要做的流程实际上是:
调用vasp(shell)->读入vasp输出文件中的能量(shell)->计算得到优化结构(Fortran)->改写vasp输入文件POSCAR(shell)->调用vasp(shell)
这样的循环,所以需要来回在shell和Fortran中互传数据
我试想了一下,版主这种方式似乎只有在读入能量给Fortran中这一步是好用的
如果互传数据只有这一步应该是可以用的,可惜不仅仅是啊
作者: fcode    时间: 2018-12-15 13:02
你可以通过Shell循环,然后把fortran 输出 write 的内容通过管道接收到,保存到内存里。
然后进行下一次循环。

这是没有问题的,我们也经常利用这种方法来做迭代。
作者: liudy02    时间: 2018-12-15 13:07
fcode 发表于 2018-12-15 13:02
你可以通过Shell循环,然后把fortran 输出 write 的内容通过管道接收到,保存到内存里。
然后进行下一次循 ...

非常感谢
你是指Fortran写的执行程序只运行一次
但是在Shell脚本里在多个管道里使用它,直到完成任务为止?
作者: liudy02    时间: 2018-12-15 14:32
fcode 发表于 2018-12-15 13:02
你可以通过Shell循环,然后把fortran 输出 write 的内容通过管道接收到,保存到内存里。
然后进行下一次循 ...

再想想,我知道了,你的意思是管道还可以继续往下接
不过怎么用循环来做迭代就想不出来了,要是版主能好心给个简单的例子就好了……
作者: fcode    时间: 2018-12-15 16:16
fortran程序执行多次
作者: liudy02    时间: 2018-12-15 16:33
fcode 发表于 2018-12-15 16:16
fortran程序执行多次

这样啊,那这样就是Fortran程序里只有一次循环的程序了
真正的循环结构在shell脚本里,这好像不是我想做的那个样子呢
不过如果把主程序写在shell脚本里,Fortran只有单次循环里的数据处理部分确实也可以哦
稍微麻烦一点大概就是Fortran程序每次被运行之后,之前的结果都“忘了”
如果嫌用文件I/O没效率的话,就需要每次来回给它和内存交互数据了
非常感谢版主的指点,我试试这种也尝试看能不能给自己编一些shell里那么好用的文字处理函数吧……




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2