python +Sed 批量文件关键字参数处理

OpenFOAM 算例批量参数修改的脚本编写过程

Posted by Mao Yanjun on December 9, 2017

“🙉🙉🙉 ”

本帖会持续更新补充,新手所写,理论不严谨,代码不简洁,逻辑不清晰,仅供学习记录参考

python +Sed 批量文件关键字参数处理

最近,随着写博客,发现必须要提高工作效率,才能有时间来写博客,同时随着逐渐的习惯的linux系统的操作方式,发现用脚本的方式来处理文件的工作真的很方便快捷。当然,前提是脚本的编写要顺利。其实学习一个新事物,最开始是最难的,坚持过了也就变好了。

脚本语言选择

  • 作为脚本语言,linux bash shell 提供了一些方便便捷的指令,用好了可以很方便。
  • python 作为一种解释型语言,在应用和文件处理上真的有很大优势。同时作为一种胶水语言,可以很方便的连接其他现有的程序。

程序需求

平时总是需要对于OpenFOAM算例参数进行设置,特别是针对于多个工况,在进行算例设置的时候,大多只需要修改一个参数,而打开文件,用交互式的方式需要反复用鼠标点开文件夹,再点开文件,再修改。特别是目标文件在目录下的子目录里面的时候,更是反复的点击鼠标。这里举个例子:五个文件夹,格式相同,目标文件在第二层子文件夹下面:基本操作流程如下:

  • 点击文件夹10次
  • 打开文件,打开editor,此部分及其耗时
  • 每个文件打开后定位到相应位置
  • 删除要修改参数
  • 写入修改参数
  • 快捷键保存,鼠标的话还要再多点五次
  • 点击关闭文件
  • 返回时最少5次

因此,想通过编写脚本,直接根据文件中的关键字进行修改,每次提示工作目录,通过键盘直接输入想要修改的参数。

程序设计思路

写程序前跟具需求,有必要进行程序设计思路进行构建,然后解决关键技术点。

  • 获取根目录下所有文件
  • 对获得的每一个文件名进行字符串连接成绝对地址,到目标修改文件的目录下
  • 待修改参数的屏幕或者文本输入
  • 对文件进行修改
  • 循环进行下一个文件的操作

开始的时候,觉得程序思路很简单,没什么难点,但是对于python新手和shell小白来讲基本上就是灾难。

遇到的困难

主要难点有一下几个:

获取文件夹中的子文件夹目录

此部分可以用python os模块,其中a = os.listdir(pathname)可以直接获得目录下的所有文件夹的名字,并赋给a作为list,list的元素都是字符串,从而后续可以使用a[i]操作每一个文件夹名进行文件拼接目标地址。

进行目录的拼接

可以使用postname=os.path.join(pathname,a[i])这样的拼接方式。关于os.path.join的操作需要深入学习。

文本的处理

计划处理的是修改关键字coeff后面的参数,并在原始文件中进行修改。

   restraints
    {
         linearPTO
        {
            sixDoFRigidBodyMotionRestraint linearDamper;
            coeff         25799.78;
        }//Damping Coefficient (Ns/m)max 20N
    }
  
}

可以本打算使用python直接完成所有操作,但是发现python在处理行上操作不是很方便,小白没有找到合适的方式。理想的修改方式是修改关键字后面的数值,并且保留分号。但是发现这样的操作我是真心不会。于是想到了对整行操作,重新整行内容。找了一圈python依旧无力。于是想到了shell 中的sed命令。正好找到了如下方式可以重写整行。sed -i '/coeff/c\coeff 15365;' potionDisplacement。于是看到了希望。 第一个是在python中调用shell 命令,这里os.system('sed -i -f script.sed' +' '+dir1+'/pointDisplacement'),可以进行shell命令的调用。

但是此处,关于如何调用,踩了大坑,()内用''的方式来引入,可以完全不用考虑字符的转义问题,此处到底用什么样式有待学习,system()命令中,直接看做字符串的拼接操作,可以调用如dir1所示的python的外部变量,(这样就不写入sed文件,然后让sed来调用了,对于关键字coeff是否可以未验证)。本文代码可能走了弯路。利用sed 可以读取.sed文件来控制格式。因此通过python 写入控制格式字符串到script.sed文件中,再利用sed来读取。采用了迂回战略。最终可以实现了批量修改指定关键参数的操作。 附代码如下:

#!/usr/bin/python
"""
Created on 2017 12 9

@author: Yanjun Mao
"""
#set the script in the top dictionary,and execute it py tpye "python ChangesParameters.py"
import os 

pathname = os.path.abspath('.')
# List of time dirs in order
a = os.listdir(pathname)
a.remove('ChangesParameters.py')
#a.remove('script.sed')
#print a
a.sort()
print 'these are all the dictionaries in the work path:'
print a
for i in range(len(a)):
    print 'this is the courent work path:'
    print a[i]
    postname=os.path.join(pathname,a[i])
    dir1 = os.path.join(postname,'0.org')
    #print dir1
    dampingCoeff=raw_input("input the dampingCoeff: ")
    f=open('script.sed','w')
    f.write('1,/coeff/c\            coeff         '+str(dampingCoeff)+';')
    f.close()
    os.system('sed -i -f script.sed' +' '+dir1+'/pointDisplacement')

print 'Done'

代码局限和注意事项

  • 关键词所在行最好没有其他参数,孤立成一行。
  • 关键词在整个文本中只出现一次,否则会全部替换了。后续调整替换范围。
  • os.system(‘sed -i -f script.sed’ +’ ‘+dir1+’/pointDisplacement’)此命令涉及到了引号嵌套,需要进一步学习,如何正确使用引号。
  • 可以通过指定行号来只对某一行进行操作,从而避免匹配到多个关键字的问题

最后

最好还是系统的学习 python 和 shell 的基础上再进行相关编程吧